Merge pull request #3893 from danielyxie/dev

2 recovery fix
This commit is contained in:
hydroflame 2022-07-06 12:43:23 -04:00 committed by GitHub
commit b55318706a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 137 additions and 128 deletions

4
dist/main.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

64
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1686,9 +1686,6 @@ export class Bladeburner implements IBladeburner {
// Operation Daedalus
if (action == null) {
throw new Error("Failed to get BlackOperation Object for: " + this.action.name);
} else if (action.name === BlackOperationNames.OperationDaedalus && this.blackops[action.name]) {
this.resetAction();
router.toBitVerse(false, false);
} else if (this.action.type != ActionTypes["BlackOperation"] && this.action.type != ActionTypes["BlackOp"]) {
this.startAction(player, this.action); // Repeat action
}
@ -1991,11 +1988,6 @@ export class Bladeburner implements IBladeburner {
// Edge race condition when the engine checks the processing counters and attempts to route before the router is initialized.
if (!router.isInitialized) return;
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
if (router.page() !== Page.BitVerse && this.blackops.hasOwnProperty(BlackOperationNames.OperationDaedalus)) {
return router.toBitVerse(false, false);
}
// If the Player starts doing some other actions, set action to idle and alert
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && player.isWorking) {
if (this.action.type !== ActionTypes["Idle"]) {

@ -4,6 +4,10 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography";
import { FactionNames } from "../../Faction/data/FactionNames";
import { use } from "../../ui/Context";
import { BlackOperationNames } from "../data/BlackOperationNames";
import { Button } from "@mui/material";
import { CorruptableText } from "../../ui/React/CorruptableText";
interface IProps {
bladeburner: IBladeburner;
@ -11,6 +15,7 @@ interface IProps {
}
export function BlackOpPage(props: IProps): React.ReactElement {
const router = use.Router();
return (
<>
<Typography>
@ -27,7 +32,13 @@ export function BlackOpPage(props: IProps): React.ReactElement {
Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank
losses.
</Typography>
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
{props.bladeburner.blackops[BlackOperationNames.OperationDaedalus] ? (
<Button sx={{ my: 1, p: 1 }} onClick={() => router.toBitVerse(false, false)}>
<CorruptableText content="Destroy w0rld_d34mon"></CorruptableText>
</Button>
) : (
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
)}
</>
);
}

@ -229,7 +229,7 @@ export const CONSTANTS: {
InfiniteLoopLimit: 2000,
Donations: 7,
Donations: 20,
LatestUpdate: `
## [draft] v1.7.0 - 2022-04-13 to 2022-05-20

@ -66,7 +66,7 @@ export function ActiveFragmentSummary(props: IProps): React.ReactElement {
</TableRow>
{summary.map((entry) => {
return (
<TableRow>
<TableRow key={entry.type}>
<TableCell sx={{ borderBottom: "none", p: 0, m: 0 }}>
<Typography>
{entry.coordinate.map((coord) => {

@ -3,7 +3,7 @@ import * as React from "react";
import { ActiveFragment } from "../ActiveFragment";
import { DummyGift } from "../DummyGift";
import { Grid } from "./Grid";
import { calculateGrid, zeros } from "../Helper";
import { zeros } from "../Helper";
interface IProps {
width: number;
@ -13,7 +13,6 @@ interface IProps {
export function DummyGrid(props: IProps): React.ReactElement {
const gift = new DummyGift(props.width, props.height, props.fragments);
const activeGrid = calculateGrid(gift);
const ghostGrid = zeros([props.width, props.height]);
return (
<Box>
@ -21,7 +20,6 @@ export function DummyGrid(props: IProps): React.ReactElement {
<Grid
width={props.width}
height={props.height}
activeGrid={activeGrid}
ghostGrid={ghostGrid}
gift={gift}
enter={() => undefined}

@ -1,13 +1,13 @@
import { TableBody, TableRow } from "@mui/material";
import * as React from "react";
import { ActiveFragment } from "../ActiveFragment";
import { calculateGrid } from "../Helper";
import { IStaneksGift } from "../IStaneksGift";
import { Cell } from "./Cell";
interface IProps {
width: number;
height: number;
activeGrid: number[][];
ghostGrid: number[][];
gift: IStaneksGift;
enter(i: number, j: number): void;
@ -32,11 +32,13 @@ function randomColor(fragment: ActiveFragment): string {
}
export function Grid(props: IProps): React.ReactElement {
const activeGrid = calculateGrid(props.gift);
function color(worldX: number, worldY: number): string {
if (props.ghostGrid[worldX][worldY] && props.activeGrid[worldX][worldY]) return "red";
if (props.ghostGrid[worldX][worldY] && activeGrid[worldX][worldY]) return "red";
if (props.ghostGrid[worldX][worldY]) return "white";
if (props.activeGrid[worldX][worldY]) {
if (activeGrid[worldX][worldY]) {
const fragment = props.gift.fragmentAt(worldX, worldY);
if (!fragment) throw new Error("ActiveFragment should not be null");
return randomColor(fragment);

@ -8,7 +8,7 @@ import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import { Table } from "../../ui/React/Table";
import { Grid } from "./Grid";
import { zeros, calculateGrid } from "../Helper";
import { zeros } from "../Helper";
import { ActiveFragmentSummary } from "./ActiveFragmentSummary";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
@ -18,7 +18,6 @@ interface IProps {
}
export function MainBoard(props: IProps): React.ReactElement {
const [grid, setGrid] = React.useState(calculateGrid(props.gift));
const [ghostGrid, setGhostGrid] = React.useState(zeros([props.gift.width(), props.gift.height()]));
const [pos, setPos] = React.useState([0, 0]);
const [rotation, setRotation] = React.useState(0);
@ -54,12 +53,10 @@ export function MainBoard(props: IProps): React.ReactElement {
if (!props.gift.canPlace(worldX, worldY, rotation, selectedFragment)) return;
props.gift.place(worldX, worldY, rotation, selectedFragment);
}
setGrid(calculateGrid(props.gift));
}
function clear(): void {
props.gift.clear();
setGrid(zeros([props.gift.width(), props.gift.height()]));
}
function updateSelectedFragment(fragment: Fragment): void {
@ -92,7 +89,6 @@ export function MainBoard(props: IProps): React.ReactElement {
<Grid
width={props.gift.width()}
height={props.gift.height()}
activeGrid={grid}
ghostGrid={ghostGrid}
gift={props.gift}
enter={(i, j) => moveGhost(i, j, rotation)}

@ -20,7 +20,7 @@ import { MathJaxWrapper } from "../../MathJaxWrapper";
import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import { NumberInput } from "../../ui/React/NumberInput";
type IProps = {
faction: Faction;
@ -31,26 +31,20 @@ type IProps = {
};
export function DonateOption(props: IProps): React.ReactElement {
const [donateAmt, setDonateAmt] = useState<number | null>(null);
const [donateAmt, setDonateAmt] = useState<number>(NaN);
const digits = (CONSTANTS.DonateMoneyToRepDivisor + "").length - 1;
function canDonate(): boolean {
if (donateAmt === null) return false;
if (isNaN(donateAmt)) return false;
if (isNaN(donateAmt) || donateAmt <= 0) return false;
if (props.p.money < donateAmt) return false;
return true;
}
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
const amt = numeralWrapper.parseMoney(event.target.value);
if (event.target.value === "" || isNaN(amt)) setDonateAmt(null);
else setDonateAmt(amt);
}
function donate(): void {
const fac = props.faction;
const amt = donateAmt;
if (amt === null) return;
if (isNaN(amt)) return;
if (!canDonate()) return;
props.p.loseMoney(amt, "other");
const repGain = repFromDonation(amt, props.p);
@ -85,8 +79,8 @@ export function DonateOption(props: IProps): React.ReactElement {
</Typography>
) : (
<>
<TextField
onChange={onChange}
<NumberInput
onChange={setDonateAmt}
placeholder={"Donation amount"}
disabled={props.disabled}
InputProps={{

@ -277,14 +277,6 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
>
Reddit
</Button>
<Button
startIcon={<Public />}
href="https://plaza.dsolver.ca/games/bitburner"
target="_blank"
sx={{ gridArea: "plaza" }}
>
Incremental game plaza
</Button>
</Box>
{!location.href.startsWith("file://") && (

@ -95,7 +95,7 @@ function wrapFunction(
boolean: helpers.boolean,
getServer: (hostname: string) => helpers.getServer(hostname, ctx),
checkSingularityAccess: () => helpers.checkSingularityAccess(functionName),
hack: helpers.hack,
hack: (hostname: any, manual: any, extra?: any) => helpers.hack(ctx, hostname, manual, extra),
getValidPort: (port: any) => helpers.getValidPort(functionPath, port),
},
};

@ -539,8 +539,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
stock: NetscriptStockMarket(Player, workerScript),
grafting: NetscriptGrafting(Player),
hacknet: NetscriptHacknet(Player, workerScript),
sprintf: sprintf,
vsprintf: vsprintf,
sprintf: () => sprintf,
vsprintf: () => vsprintf,
scan:
(ctx: NetscriptContext) =>
(_hostname: unknown = workerScript.hostname): string[] => {

@ -725,7 +725,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
const employeeName = ctx.helper.string("employeeName", _employeeName);
const job = ctx.helper.string("job", _job);
const employee = getEmployee(divisionName, cityName, employeeName);
return netscriptDelay(1000, workerScript).then(function () {
return netscriptDelay(["Training", "Unassigned"].includes(employee.pos) ? 0 : 1000, workerScript).then(function () {
return Promise.resolve(AssignJob(employee, job));
});
},

@ -598,38 +598,37 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const server = player.getCurrentServer();
return _ctx.helper.hack(server.hostname, true);
},
installBackdoor: (_ctx: NetscriptContext) =>
function (): Promise<void> {
_ctx.helper.checkSingularityAccess();
const baseserver = player.getCurrentServer();
if (!(baseserver instanceof Server)) {
_ctx.log(() => "cannot backdoor this kind of server");
return Promise.resolve();
installBackdoor: (_ctx: NetscriptContext) => async (): Promise<void> => {
_ctx.helper.checkSingularityAccess();
const baseserver = player.getCurrentServer();
if (!(baseserver instanceof Server)) {
_ctx.log(() => "cannot backdoor this kind of server");
return Promise.resolve();
}
const server = baseserver;
const installTime = (calculateHackingTime(server, player) / 4) * 1000;
// No root access or skill level too low
const canHack = netscriptCanHack(server, player);
if (!canHack.res) {
throw _ctx.helper.makeRuntimeErrorMsg(canHack.msg || "");
}
_ctx.log(
() => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`,
);
return netscriptDelay(installTime, workerScript).then(function () {
_ctx.log(() => `Successfully installed backdoor on '${server.hostname}'`);
server.backdoorInstalled = true;
if (SpecialServers.WorldDaemon === server.hostname) {
Router.toBitVerse(false, false);
}
const server = baseserver ;
const installTime = (calculateHackingTime(server, player) / 4) * 1000;
// No root access or skill level too low
const canHack = netscriptCanHack(server, player);
if (!canHack.res) {
throw _ctx.helper.makeRuntimeErrorMsg(canHack.msg || "");
}
_ctx.log(
() => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`,
);
return netscriptDelay(installTime, workerScript).then(function () {
_ctx.log(() => `Successfully installed backdoor on '${server.hostname}'`);
server.backdoorInstalled = true;
if (SpecialServers.WorldDaemon === server.hostname) {
Router.toBitVerse(false, false);
}
return Promise.resolve();
});
},
return Promise.resolve();
});
},
isFocused: (_ctx: NetscriptContext) =>
function (): boolean {
_ctx.helper.checkSingularityAccess();

@ -1854,7 +1854,11 @@ export function getNextCompanyPosition(
}
export function quitJob(this: IPlayer, company: string, _sing = false): void {
if (this.isWorking == true && this.workType !== WorkType.Company && this.companyName == company) {
if (
this.isWorking === true &&
[WorkType.Company, WorkType.CompanyPartTime].includes(this.workType) &&
this.companyName === company
) {
this.finishWork(true);
}
delete this.jobs[company];
@ -2287,7 +2291,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!fulcrumsecrettechonologiesFac.isMember &&
!fulcrumsecrettechonologiesFac.alreadyInvited &&
fulcrumSecretServer.backdoorInstalled &&
checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)
checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies)
) {
invitedFactions.push(fulcrumsecrettechonologiesFac);
}

@ -3257,7 +3257,7 @@ export interface Bladeburner {
* @remarks
* RAM cost: 0 GB
*
* Returns the amount of accumulated bonus time (seconds) for the Bladeburner mechanic.
* Returns the amount of accumulated bonus time (milliseconds) for the Bladeburner mechanic.
*
* Bonus time is accumulated when the game is offline or if the game is inactive in the browser.
*
@ -3594,7 +3594,7 @@ export interface Gang {
* @remarks
* RAM cost: 0 GB
*
* Returns the amount of accumulated bonus time (seconds) for the Gang mechanic.
* Returns the amount of accumulated bonus time (milliseconds) for the Gang mechanic.
*
* Bonus time is accumulated when the game is offline or if the game is inactive in the browser.
*

@ -272,18 +272,20 @@ const Engine: {
const numCyclesOffline = Math.floor(timeOffline / CONSTANTS._idleSpeed);
// Generate coding contracts
let numContracts = 0;
if (numCyclesOffline < 3000 * 100) {
// if we have less than 100 rolls, just roll them exactly.
for (let i = 0; i < numCyclesOffline / 3000; i++) {
if (Math.random() < 0.25) numContracts++;
if (Player.sourceFiles.length > 0) {
let numContracts = 0;
if (numCyclesOffline < 3000 * 100) {
// if we have less than 100 rolls, just roll them exactly.
for (let i = 0; i < numCyclesOffline / 3000; i++) {
if (Math.random() < 0.25) numContracts++;
}
} else {
// just average it.
numContracts = (numCyclesOffline / 3000) * 0.25;
}
for (let i = 0; i < numContracts; i++) {
generateRandomContract();
}
} else {
// just average it.
numContracts = (numCyclesOffline / 3000) * 0.25;
}
for (let i = 0; i < numContracts; i++) {
generateRandomContract();
}
let offlineReputation = 0;

@ -0,0 +1,19 @@
import { TextField, StandardTextFieldProps } from "@mui/material";
import React from "react";
import { numeralWrapper } from "../numeralFormat";
interface IProps extends Omit<StandardTextFieldProps, "onChange"> {
onChange: (v: number) => void;
}
export function NumberInput(props: IProps): React.ReactElement {
const textProps = {
...props,
onChange: (event: React.ChangeEvent<HTMLInputElement>) => {
const amt = numeralWrapper.parseMoney(event.target.value);
if (event.target.value === "" || isNaN(amt)) props.onChange(NaN);
else props.onChange(amt);
},
};
return <TextField {...textProps} />;
}