DNET: Tweaks from player feedback (#2593)

This commit is contained in:
Michael Ficocelli
2026-03-26 18:38:45 -07:00
committed by GitHub
parent 38d5f3b364
commit fdd6d65c25
10 changed files with 96 additions and 54 deletions

View File

@@ -17,3 +17,7 @@ getCurrentPlayer(): "White" | "Black" | "None";
"White" \| "Black" \| "None"
## Remarks
RAM cost: 0 GB

View File

@@ -22,3 +22,7 @@ getGameState(): {
{ currentPlayer: "White" \| "Black" \| "None"; whiteScore: number; blackScore: number; previousMove: \[number, number\] \| null; komi: number; bonusCycles: number; }
## Remarks
RAM cost: 0 GB

View File

@@ -31,3 +31,7 @@ getMoveHistory(): string[][];
string\[\]\[\]
## Remarks
RAM cost: 0 GB

View File

@@ -15,3 +15,7 @@ getOpponent(): GoOpponent;
[GoOpponent](./bitburner.goopponent.md)
## Remarks
RAM cost: 0 GB

View File

@@ -31,6 +31,7 @@ type LabDetails = {
mazeWidth: number;
mazeHeight: number;
manual: boolean;
offsetStartAndEnd: boolean;
};
export const labData: Record<string, LabDetails> = {
@@ -41,6 +42,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 20,
mazeHeight: 14,
manual: true,
offsetStartAndEnd: false,
},
[SpecialServers.CruelLab]: {
name: SpecialServers.CruelLab,
@@ -49,6 +51,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 30,
mazeHeight: 20,
manual: true,
offsetStartAndEnd: false,
},
[SpecialServers.MercilessLab]: {
name: SpecialServers.MercilessLab,
@@ -57,6 +60,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 40,
mazeHeight: 26,
manual: false,
offsetStartAndEnd: false,
},
[SpecialServers.UberLab]: {
name: SpecialServers.UberLab,
@@ -65,6 +69,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 60,
mazeHeight: 40,
manual: false,
offsetStartAndEnd: true,
},
[SpecialServers.EternalLab]: {
name: SpecialServers.EternalLab,
@@ -73,6 +78,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 60,
mazeHeight: 40,
manual: false,
offsetStartAndEnd: true,
},
[SpecialServers.EndlessLab]: {
name: SpecialServers.EndlessLab,
@@ -81,6 +87,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 60,
mazeHeight: 40,
manual: false,
offsetStartAndEnd: true,
},
[SpecialServers.FinalLab]: {
name: SpecialServers.FinalLab,
@@ -89,6 +96,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 60,
mazeHeight: 40,
manual: false,
offsetStartAndEnd: true,
},
[SpecialServers.BonusLab]: {
name: SpecialServers.BonusLab,
@@ -97,6 +105,7 @@ export const labData: Record<string, LabDetails> = {
mazeWidth: 60,
mazeHeight: 40,
manual: false,
offsetStartAndEnd: true,
},
} as const;
@@ -185,6 +194,7 @@ export const getSurroundingsVisualized = (
showEnd = false,
): string => {
const result: string[] = [];
const [endpointY, endpointX] = DarknetState.labEndpoint ?? [maze[0].length - 2, maze.length - 2];
for (let i = y - range; i <= y + range; i++) {
let row = "";
for (let j = x - range; j <= x + range; j++) {
@@ -192,7 +202,7 @@ export const getSurroundingsVisualized = (
row += "@";
continue;
}
if (i === maze.length - 2 && j === maze[0].length - 2 && showEnd) {
if (i === endpointX && j === endpointY && showEnd) {
row += "X";
continue;
}
@@ -205,7 +215,7 @@ export const getSurroundingsVisualized = (
};
const getLocationStatus = (pid: number): LocationStatus => {
const [initialX, initialY] = DarknetState.labLocations[pid] ?? [1, 1];
const [initialX, initialY] = getPositionInLab(pid);
const surroundings = getSurroundingsVisualized(getLabMaze(), initialX, initialY).split("\n");
return {
coords: [initialX, initialY],
@@ -245,11 +255,8 @@ export const handleLabyrinthPassword = (
}
const maze = getLabMaze();
if (!DarknetState.labLocations[pid]) {
DarknetState.labLocations[pid] = [1, 1];
}
const [initialX, initialY] = DarknetState.labLocations[pid];
const end = [maze[0].length - 2, maze.length - 2];
const [initialX, initialY] = getPositionInLab(pid);
const end = DarknetState.labEndpoint ?? [maze[0].length - 2, maze.length - 2];
const [dx, dy] = getDirectionFromInput(attemptedPassword);
const newLocation: [number, number] = [initialX + dx * 2, initialY + dy * 2];
@@ -324,6 +331,12 @@ export const handleLabyrinthPassword = (
};
};
export const getPositionInLab = (pid: number): [number, number] => {
const [offsetX, offsetY] = getRandomOffset();
DarknetState.labLocations[pid] ??= [1 + offsetX, 1 + offsetY];
return DarknetState.labLocations[pid];
};
const getDirectionFromInput = (input: string): number[] => {
const direction = input
.split(" ")
@@ -352,10 +365,22 @@ export const getLabMaze = (): string[] => {
if (!DarknetState.labyrinth) {
const { mazeWidth, mazeHeight } = getLabyrinthDetails();
DarknetState.labyrinth = generateMaze(mazeWidth, mazeHeight);
const [offsetX, offsetY] = getRandomOffset();
DarknetState.labEndpoint = [
DarknetState.labyrinth[0].length - 2 - offsetX,
DarknetState.labyrinth.length - 2 - offsetY,
];
}
return DarknetState.labyrinth;
};
const getRandomOffset = () => {
const { offsetStartAndEnd } = getLabyrinthDetails();
const offsetX = offsetStartAndEnd ? Math.floor(Math.random() * 3) * 2 : 0;
const offsetY = offsetStartAndEnd ? Math.floor(Math.random() * 3) * 2 : 0;
return [offsetX, offsetY];
};
export const getLabyrinthServerNames = () => {
const labHostnames: string[] = Object.keys(labData);
return labHostnames;
@@ -455,6 +480,7 @@ export const getLabyrinthDetails = (): {
mazeHeight: number;
cha: number;
name: string;
offsetStartAndEnd: boolean;
} => {
// Lab not unlocked yet
if (!hasFullDarknetAccess()) {
@@ -466,6 +492,7 @@ export const getLabyrinthDetails = (): {
lab: null,
depth: 5,
manual: false,
offsetStartAndEnd: false,
};
}
@@ -480,6 +507,7 @@ export const getLabyrinthDetails = (): {
mazeHeight: labDetails.mazeHeight,
cha: labDetails.cha,
name: labDetails.name,
offsetStartAndEnd: labDetails.offsetStartAndEnd,
};
};

View File

@@ -40,11 +40,12 @@ export const DarknetState = {
Network: new Array(MAX_NET_DEPTH).fill(null).map(() => new Array<DarknetServer | null>(NET_WIDTH).fill(null)),
labyrinth: null as string[] | null,
labEndpoint: null as [number, number] | null,
/**
* This property may contain data of dead PIDs. Call cleanUpLabyrinthLocations before using this property if you
* want to get data of alive PIDs.
*/
labLocations: { "-1": [1, 1] } as Record<number, [number, number] | undefined>,
labLocations: {} as Record<number, [number, number] | undefined>,
lastPhishingCacheTime: new Date(),
lastCctRewardTime: new Date(),
@@ -90,7 +91,7 @@ export function prestigeDarknetState(prestigeSourceFile: boolean): void {
DarknetState.cyclesSinceLastMutation = 0;
DarknetState.Network = new Array(MAX_NET_DEPTH).fill(null).map(() => new Array<null>(NET_WIDTH).fill(null));
DarknetState.labyrinth = null;
DarknetState.labLocations = { "-1": [1, 1] };
DarknetState.labLocations = {};
DarknetState.lastPhishingCacheTime = new Date();
DarknetState.lastStormTime = new Date();
DarknetState.stockPromotions = {};

View File

@@ -144,7 +144,7 @@ export const LabyrinthSummary = ({ isAuthenticating }: LabyrinthSummaryProps): R
<>
<div className={classes.inlineFlexBox}>
<div style={{ width: "50%" }}>
{!lab.manual ? (
{!lab.manual && currentPerspective === -1 ? (
<Typography style={{ fontStyle: "italic", paddingRight: "10px" }}>
This lab cannot be completed manually. Select a script PID that is attempting the labyrinth from the
options below to view its progress.

View File

@@ -120,51 +120,35 @@ export function NetworkDisplayWrapper(): React.ReactElement {
}
};
const zoomIn = useCallback(() => {
if (zoomIndex >= zoomOptions.length - 1) {
return;
}
DarknetState.zoomIndex = Math.max(zoomIndex + 1, 0);
setZoomIndex(DarknetState.zoomIndex);
const zoom = zoomOptions[zoomIndex];
const background = draggableBackground.current;
scrollTo(
(background?.scrollTop ?? 0) + ((background?.clientHeight ?? 0) / 4) * zoom,
(background?.scrollLeft ?? 0) + ((background?.clientWidth ?? 0) / 4) * zoom,
);
}, [zoomIndex, setZoomIndex, zoomOptions, scrollTo]);
const zoomOut = useCallback(() => {
if (zoomIndex <= 0) {
return;
}
DarknetState.zoomIndex = Math.min(zoomIndex - 1, zoomOptions.length - 1);
setZoomIndex(DarknetState.zoomIndex);
const zoom = zoomOptions[zoomIndex];
const background = draggableBackground.current;
scrollTo(
(background?.scrollTop ?? 0) - ((background?.clientHeight ?? 0) / 4) * zoom,
(background?.scrollLeft ?? 0) - ((background?.clientWidth ?? 0) / 4) * zoom,
);
}, [zoomIndex, setZoomIndex, zoomOptions, scrollTo]);
const changeZoom = useCallback(
(out = true, mouseX?: number, mouseY?: number) => {
if (out && zoomIndex <= 0) return;
if (!out && zoomIndex >= zoomOptions.length - 1) return;
const newZoomIndex = out ? zoomIndex - 1 : zoomIndex + 1;
const oldZoom = zoomOptions[zoomIndex];
const newZoom = zoomOptions[newZoomIndex];
DarknetState.zoomIndex = newZoomIndex;
setZoomIndex(newZoomIndex);
const background = draggableBackground.current;
const mx = mouseX ?? (background?.clientWidth ?? 0) / 2;
const my = mouseY ?? (background?.clientHeight ?? 0) / 2;
scrollTo(
(((background?.scrollTop ?? 0) + my) / oldZoom) * newZoom - my,
(((background?.scrollLeft ?? 0) + mx) / oldZoom) * newZoom - mx,
);
},
[zoomIndex, setZoomIndex, zoomOptions, scrollTo],
);
const zoom = useCallback(
(wheelEvent: WheelEvent) => {
const target = wheelEvent.target as HTMLDivElement;
if (!draggableBackground.current || DarknetState.openServer) {
return;
}
if (wheelEvent.deltaY < 0) {
zoomIn();
} else {
zoomOut();
}
if (!target?.parentElement?.getBoundingClientRect()) {
return;
}
if (!draggableBackground.current || DarknetState.openServer) return;
const rect = draggableBackground.current.getBoundingClientRect();
const mouseX = wheelEvent.clientX - rect.left;
const mouseY = wheelEvent.clientY - rect.top;
changeZoom(wheelEvent.deltaY > 0, mouseX, mouseY);
},
[draggableBackground, zoomOut, zoomIn],
[draggableBackground, changeZoom],
);
const zoomRef = useRef(zoom);
@@ -311,10 +295,10 @@ export function NetworkDisplayWrapper(): React.ReactElement {
</div>
</div>
<div className={classes.zoomContainer}>
<Button className={classes.button} onClick={() => zoomIn()}>
<Button className={classes.button} onClick={() => changeZoom(false)}>
<ZoomIn />
</Button>
<Button className={classes.button} onClick={() => zoomOut()}>
<Button className={classes.button} onClick={() => changeZoom()}>
<ZoomOut />
</Button>
</div>

View File

@@ -21,6 +21,7 @@ import { getPasswordType } from "../DarkNet/controllers/ServerGenerator";
import { checkPassword, getAuthResult, isAuthenticated } from "../DarkNet/effects/authentication";
import {
getLabMaze,
getPositionInLab,
getLabyrinthDetails,
getLabyrinthLocationReport,
getSurroundingsVisualized,
@@ -695,7 +696,7 @@ export function NetscriptDarknet(): InternalAPI<DarknetAPI> {
const authenticationTime = calculateAuthenticationTime(lab, Player, ctx.workerScript.scriptRef.threads);
await helpers.netscriptDelay(ctx, authenticationTime);
const [x, y] = DarknetState.labLocations[pid] ?? [1, 1];
const [x, y] = getPositionInLab(pid);
return {
success: true,
message: getSurroundingsVisualized(getLabMaze(), x, y, 3, true, true),

View File

@@ -5646,12 +5646,18 @@ export interface Go {
* ".XO.#",
*
*]
*
* @remarks
* RAM cost: 0 GB
*/
getMoveHistory(): string[][];
/**
* Returns the color of the current player, or 'None' if the game is over.
* @returns "White" | "Black" | "None"
*
* @remarks
* RAM cost: 0 GB
*/
getCurrentPlayer(): "White" | "Black" | "None";
@@ -5659,6 +5665,9 @@ export interface Go {
* Gets the status of the current game.
* Shows the current player, current score, and the previous move coordinates.
* Previous move will be null for a pass, or if there are no prior moves.
*
* @remarks
* RAM cost: 0 GB
*/
getGameState(): {
currentPlayer: "White" | "Black" | "None";
@@ -5671,6 +5680,9 @@ export interface Go {
/**
* Returns the name of the opponent faction in the current subnet.
*
* @remarks
* RAM cost: 0 GB
*/
getOpponent(): GoOpponent;