More work on bn14

This commit is contained in:
Your Name 2023-07-17 17:33:22 -04:00
parent 449e371dc3
commit 6924d27ba7
12 changed files with 244 additions and 187 deletions

@ -1,3 +1,12 @@
import { Reviver } from "../utils/JSONReviver";
import { Myrian } from "./Myrian";
export const myrian = new Myrian();
export let myrian = new Myrian();
export function loadMyrian(saveString: string): void {
if (saveString) {
myrian = JSON.parse(saveString, Reviver);
} else {
myrian = new Myrian();
}
}

@ -1,13 +1,45 @@
import { SleeveMyrianWork } from "../PersonObjects/Sleeve/Work/SleeveMyrianWork";
import { DefaultWorld } from "./World";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
import { Player } from "@player";
interface MyrianSleeve {
index: number;
x: number;
y: number;
}
export class Myrian {
world: string[][];
resources: number;
world: string[][] = [];
resources = 0;
sleeves: MyrianSleeve[] = [];
constructor() {
this.world = DefaultWorld;
this.resources = 0;
console.log(this);
}
}
constructor() {
this.world = DefaultWorld;
this.resources = 0;
}
joinSleeve(sleeveId: number) {
if (this.sleeves.find((m) => m.index === sleeveId)) return;
const spawn = this.findSleeveSpawnPoint();
Player.sleeves[sleeveId].startWork(new SleeveMyrianWork());
this.sleeves.push({ index: sleeveId, x: spawn[0], y: spawn[0] });
}
findSleeveSpawnPoint(): [number, number] {
// Wrong but will do for now
return [1, 1];
}
/** Serialize the current object to a JSON save state. */
toJSON(): IReviverValue {
return Generic_toJSON("Myrian", this);
}
/** Initializes a Myrian object from a JSON save state. */
static fromJSON(value: IReviverValue): Myrian {
return Generic_fromJSON(Myrian, value.data);
}
}
constructorsForReviver.Myrian = Myrian;

@ -1,67 +1,71 @@
import React, { useEffect, useState } from "react";
import Container from "@mui/material/Container";
import { Box } from "@mui/system";
import { Paper, Typography } from "@mui/material";
import { useRerender } from "src/ui/React/hooks";
import { Myrian } from "../Myrian";
import PersonIcon from '@mui/icons-material/Person';
import BatteryFullIcon from '@mui/icons-material/BatteryFull';
import Battery20Icon from '@mui/icons-material/Battery20';
import FavoriteIcon from '@mui/icons-material/Favorite';
const width = 30;
const height = 30;
import PersonIcon from "@mui/icons-material/Person";
import BatteryFullIcon from "@mui/icons-material/BatteryFull";
import Battery20Icon from "@mui/icons-material/Battery20";
import FavoriteIcon from "@mui/icons-material/Favorite";
const iterator = (i: number): number[] => {
return Array(i).fill(0)
}
return Array(i).fill(0);
};
interface ICellProps {
tile: string;
tile: string;
}
const Cell = ({ tile }: ICellProps): React.ReactElement => {
const x = 50;
const sx = {
display: 'block',
color: 'white',
fontSize: x + 'px',
}
return <div style={{
width: x + 'px', height: x + 'px', margin: '0px', padding: '0px'
}}>
{tile === '' && <div />}
{tile === 'b' && <BatteryFullIcon sx={sx} />}
{tile === 'd' && <Battery20Icon sx={sx} />}
{tile === 'c' && <FavoriteIcon sx={sx} />}
const x = 50;
const sx = {
display: "block",
color: "white",
fontSize: x + "px",
};
return (
<div
style={{
width: x + "px",
height: x + "px",
margin: "0px",
padding: "0px",
}}
>
{tile === "" && <div />}
{tile === "b" && <BatteryFullIcon sx={sx} />}
{tile === "d" && <Battery20Icon sx={sx} />}
{tile === "c" && <FavoriteIcon sx={sx} />}
{tile === "s" && <PersonIcon sx={sx} />}
</div>
}
);
};
interface IProps {
myrian: Myrian;
myrian: Myrian;
}
export function MyrianRoot({ myrian }: IProps): React.ReactElement {
const [render, setRerender] = useState(false);
const rerender = () => setRerender((old) => !old);
useEffect(() => {
const intervalID = setInterval(rerender, 200);
return () => clearInterval(intervalID);
}, []);
const [, setRerender] = useState(false);
const rerender = () => setRerender((old) => !old);
useEffect(() => {
const intervalID = setInterval(rerender, 200);
return () => clearInterval(intervalID);
}, []);
return (
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
<Box sx={{ display: 'flex', flexDirection: 'column', m: 0, p: 0 }}>
{iterator(myrian.world.length).map((_, j) =>
<Box sx={{ display: 'flex', flexDirection: 'row' }}>
{iterator(myrian.world[j].length).map((_, i) =>
<Cell key={i + '' + j + '' + myrian.world[j][i]} tile={myrian.world[j][i]} />)
}
</Box>)
}
</Box>
</Container>
);
const sleeves = Object.fromEntries(myrian.sleeves.map((s) => [`${s.x}_${s.y}`, s]));
return (
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
<Box sx={{ display: "flex", flexDirection: "column", m: 0, p: 0 }}>
{iterator(myrian.world.length).map((_, j) => (
<Box key={myrian.world[j].join("") + j} sx={{ display: "flex", flexDirection: "row" }}>
{iterator(myrian.world[j].length).map((_, i) => (
<Cell key={i + "" + j + "" + myrian.world[j][i]} tile={sleeves[`${i}_${j}`] ? "s" : myrian.world[j][i]} />
))}
</Box>
))}
</Box>
</Container>
);
}

@ -326,15 +326,15 @@ const stanek = {
} as const;
const myr = {
ianInteract: 5.9,
ianUse: 5.9,
ianMove: 3.4,
ianGetTask: 1.1,
ianCancelTask: 1.2,
ianEnter: 0.2,
ianLeave: 0.2,
ianBuild: 4.1,
ianDeploy: 4.1,
ianApplyPowerup: 10.9,
}
};
// UI API
const ui = {

@ -1,41 +1,51 @@
import { Myr as IMyrian } from "@nsdefs";
import { InternalAPI } from "src/Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
import { Player as player } from "../Player";
import { SleeveMyrianWork } from "../PersonObjects/Sleeve/Work/SleeveMyrianWork";
import { myrian } from "../Myrian/Helpers";
export function NetscriptMyrian(): InternalAPI<IMyrian> {
return {
ianInteract:
(ctx) =>
(sleeveId, x, y) => { throw new Error("Unimplemented"); },
ianMove:
(ctx) =>
(sleeveId, x, y) => { throw new Error("Unimplemented"); },
ianGetTask:
(ctx) =>
(sleeveId) => { throw new Error("Unimplemented"); },
ianCancelTask:
(ctx) =>
(sleeveId) => { throw new Error("Unimplemented"); },
ianEnter:
(ctx) =>
(sleeveId?) => {
const id = sleeveId === undefined ? undefined : helpers.number(ctx, "sleeveId", sleeveId);
if (id === undefined) return false; // skip player handling for now.
// handle sleeve entering the myrian.
player.sleeves[id].startWork(new SleeveMyrianWork());
return true;
},
ianLeave:
(ctx) =>
(sleeveId?) => { throw new Error("Unimplemented"); },
ianBuild:
(ctx) =>
(sleeveId, buildingId, x, y) => { throw new Error("Unimplemented"); },
ianApplyPowerup:
(ctx) =>
(sleeveId, stat) => { throw new Error("Unimplemented"); },
}
}
return {
ianUse: (ctx) => (_sleeveId, _x, _y) => {
throw new Error("Unimplemented");
},
ianMove: (ctx) => async (_sleeveId, _x, _y) => {
const id = helpers.number(ctx, "sleeveId", _sleeveId);
const x = helpers.number(ctx, "x", _x);
const y = helpers.number(ctx, "y", _y);
if (!player.sleeves[id]) throw new Error(`No sleeve with index ${id}`);
const myrSleeve = myrian.sleeves.find((s) => s.index === id);
if (!myrSleeve) return Promise.resolve();
const dist = Math.abs(myrSleeve.x - x) + Math.abs(myrSleeve.y - y);
if (dist > 1) return Promise.resolve();
return helpers.netscriptDelay(ctx, 1000).then(function () {
myrSleeve.x = x;
myrSleeve.y = y;
return Promise.resolve();
});
},
ianGetTask: (ctx) => (_sleeveId) => {
throw new Error("Unimplemented");
},
ianCancelTask: (ctx) => (_sleeveId) => {
throw new Error("Unimplemented");
},
ianEnter: (ctx) => (sleeveId?) => {
const id = sleeveId === undefined ? undefined : helpers.number(ctx, "sleeveId", sleeveId);
if (id === undefined) return false; // skip player handling for now.
// handle sleeve entering the myrian.
if (!player.sleeves[id]) throw new Error(`No sleeve with index ${id}`);
myrian.joinSleeve(id);
return true;
},
ianLeave: (ctx) => (_sleeveId?) => {
throw new Error("Unimplemented");
},
ianDeploy: (ctx) => (_sleeveId, _deploymentId, _x, _y) => {
throw new Error("Unimplemented");
},
ianApplyPowerup: (ctx) => (_sleeveId, _stat) => {
throw new Error("Unimplemented");
},
};
}

@ -1,29 +1,28 @@
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { Work, WorkType } from "./Work";
import { calculateIntelligenceBonus } from "../../formulas/intelligence";
import { SleeveWork, SleeveWorkClass, SleeveWorkType } from "./Work";
export const isSleeveMyrianWork = (w: Work | null): w is SleeveMyrianWork =>
w !== null && w.type === WorkType.MYRIAN;
export const isSleeveMyrianWork = (w: SleeveWork | null): w is SleeveMyrianWork =>
w !== null && w.type === SleeveWorkType.MYRIAN;
export class SleeveMyrianWork extends Work {
type: WorkType.MYRIAN = WorkType.MYRIAN;
export class SleeveMyrianWork extends SleeveWorkClass {
type: SleeveWorkType.MYRIAN = SleeveWorkType.MYRIAN;
process(sleeve: Sleeve, cycles: number) { }
process(sleeve: Sleeve, cycles: number) {}
APICopy() {
return { type: WorkType.MYRIAN as "MYRIAN" };
}
APICopy() {
return { type: SleeveWorkType.MYRIAN as "MYRIAN" };
}
/** Serialize the current object to a JSON save state. */
toJSON(): IReviverValue {
return Generic_toJSON("SleeveRecoveryWork", this);
}
/** Serialize the current object to a JSON save state. */
toJSON(): IReviverValue {
return Generic_toJSON("SleeveRecoveryWork", this);
}
/** Initializes a RecoveryWork object from a JSON save state. */
static fromJSON(value: IReviverValue): SleeveMyrianWork {
return Generic_fromJSON(SleeveMyrianWork, value.data);
}
/** Initializes a RecoveryWork object from a JSON save state. */
static fromJSON(value: IReviverValue): SleeveMyrianWork {
return Generic_fromJSON(SleeveMyrianWork, value.data);
}
}
constructorsForReviver.SleeveMyrianWork = SleeveMyrianWork;

@ -57,8 +57,8 @@ function getWorkDescription(sleeve: Sleeve, progress: number): string {
"This sleeve is currently attempting to infiltrate synthoid communities to generate additional contracts and operations.\nThis activity is less efficient the more sleeves are assigned to it.\n\n" +
`Progress: ${formatPercent(progress)}`
);
case WorkType.MYRIAN:
return "This sleeve is currently in The Myrian."
case SleeveWorkType.MYRIAN:
return "This sleeve is currently in The Myrian.";
}
}

@ -217,7 +217,7 @@ const tasks: {
},
["In The Myrian"]: (): ITaskDetails => {
return { first: ["------"], second: () => ["------"] };
}
},
};
const canDo: {
@ -243,7 +243,7 @@ const canDo: {
"Perform Bladeburner Actions": () => !!Player.bladeburner,
"Shock Recovery": (sleeve: Sleeve) => sleeve.shock > 0,
Synchronize: (sleeve: Sleeve) => sleeve.sync < 100,
["In The Myrian"]: (sleeve: Sleeve) => true,
["In The Myrian"]: () => true,
};
function getABC(sleeve: Sleeve): [string, string, string] {
@ -285,7 +285,7 @@ function getABC(sleeve: Sleeve): [string, string, string] {
return ["Shock Recovery", "------", "------"];
case SleeveWorkType.SYNCHRO:
return ["Synchronize", "------", "------"];
case WorkType.MYRIAN:
case SleeveWorkType.MYRIAN:
return ["In The Myrian", "------", "------"];
}
}

@ -38,6 +38,7 @@ import { Corporation } from "./Corporation/Corporation";
import { Terminal } from "./Terminal";
import { getRecordValues } from "./Types/Record";
import { ExportMaterial } from "./Corporation/Actions";
import { loadMyrian, myrian } from "./Myrian/Helpers";
/* SaveObject.js
* Defines the object used to save/load games
@ -85,6 +86,7 @@ class BitburnerSaveObject {
AllGangsSave = "";
LastExportBonus = "0";
StaneksGiftSave = "";
myrianSave = "";
getSaveString(forceExcludeRunningScripts = false): string {
this.PlayerSave = JSON.stringify(Player);
@ -104,6 +106,7 @@ class BitburnerSaveObject {
this.VersionSave = JSON.stringify(CONSTANTS.VersionNumber);
this.LastExportBonus = JSON.stringify(ExportBonus.LastExportBonus);
this.StaneksGiftSave = JSON.stringify(staneksGift);
this.myrianSave = JSON.stringify(myrian);
if (Player.gang) this.AllGangsSave = JSON.stringify(AllGangs);
@ -716,6 +719,12 @@ function loadGame(saveString: string): boolean {
loadCompanies(saveObj.CompaniesSave);
loadFactions(saveObj.FactionsSave);
if (Object.hasOwn(saveObj, "myrianSave")) {
loadMyrian(saveObj.myrianSave);
} else {
console.warn(`Could not load Staneks Gift from save`);
loadMyrian("");
}
if (Object.hasOwn(saveObj, "StaneksGiftSave")) {
loadStaneksGift(saveObj.StaneksGiftSave);
} else {
@ -811,9 +820,9 @@ function createNewUpdateText() {
() =>
dialogBoxCreate(
"New update!\n" +
"Please report any bugs/issues through the GitHub repository " +
"or the Bitburner subreddit (reddit.com/r/bitburner).\n\n" +
CONSTANTS.LatestUpdate,
"Please report any bugs/issues through the GitHub repository " +
"or the Bitburner subreddit (reddit.com/r/bitburner).\n\n" +
CONSTANTS.LatestUpdate,
),
1000,
);

@ -2719,90 +2719,82 @@ export interface Hacknet {
*/
export interface Myr {
/**
* Interact with an object in The Myrian.
* @remarks
f
*
* The effect is different depending on the object.
* Interacting with an enemy will attack it.
* With a resource node will mine it.
* With a power up will collect it.
* With a rock will try to break it.
*
* @returns Amount of milliseconds the operation will take.
*/
ianInteract(sleeveId: number, x: number, y: number): number;
* Interact with an object in The Myrian.
* @remarks
*
* The effect is different depending on the object.
* Interacting with an enemy will attack it.
* With a resource node will mine it.
* With a power up will collect it.
* With a rock will try to break it.
*
* @returns Amount of milliseconds the operation will take.
*/
ianUse(sleeveId: number, x: number, y: number): number;
/**
* Move a sleeve in the Myrian.
* @remarks
f
*
* The target tile must be 1 tile away from the sleeves current tile.
*
* @returns Amount of milliseconds the operation will take.
*/
ianMove(sleeveId: number, x: number, y: number): number;
* Move a sleeve in the Myrian.
* @remarks
*
* The target tile must be 1 tile away from the sleeves current tile.
*
* @returns Amount of milliseconds the operation will take.
*/
ianMove(sleeveId: number, x: number, y: number): Promise<void>;
/**
* Get that sleeves current task in the Myrian.
* @remarks
f
*
*
* @returns The task currently being performed.
*/
* Get that sleeves current task in the Myrian.
* @remarks
*
*
* @returns The task currently being performed.
*/
ianGetTask(sleeveId): any;
/**
* Cancel a sleeves current Myrian task.
* @remarks
f
*
* @returns true if a task was cancelled.
*/
* Cancel a sleeves current Myrian task.
* @remarks
*
* @returns true if a task was cancelled.
*/
ianCancelTask(sleeveId): boolean;
/**
* Makes the player or a sleeve enter The Myrian.
* @remarks
f
*
* @returns true if the person is now in The Myrian.
*/
* Makes the player or a sleeve enter The Myrian.
* @remarks
*
* @returns true if the person is now in The Myrian.
*/
ianEnter(sleeveId?: number): boolean;
/**
* Makes the player or a sleeve leave The Myrian.
* @remarks
f
*
* Sleeves must be 1 tile away from the core.
*
* @returns true if the person is now in the simulated world.
*/
* Makes the player or a sleeve leave The Myrian.
* @remarks
*
* Sleeves must be 1 tile away from the core.
*
* @returns true if the person is now in the simulated world.
*/
ianLeave(sleeveId?: number): boolean;
/**
* Build an entity in The Myrian.
* @remarks
f
*
* Sleeves must be 1 tile away from the target tile and the player must have enough resources to build the entity.
*
* @returns The amount of milliseconds needed to complete the operation. or -1 if failed.
*/
ianBuild(sleeveId: number, buildingId: number, x: number, y: number): number;
* Deploy an entity in The Myrian.
* @remarks
*
* Sleeves must be 1 tile away from the target tile and the player must have enough resources to build the entity.
*
* @returns The amount of milliseconds needed to complete the operation. or -1 if failed.
*/
ianDeploy(sleeveId: number, deploymentId: number, x: number, y: number): number;
/**
* Apply a Myrian powerup to a sleeve.
* @remarks
f
*
* Must have at least 1 powerup to apply.
*
* @returns True if the powerup was applied.
*/
* Apply a Myrian powerup to a sleeve.
* @remarks
*
* Must have at least 1 powerup to apply.
*
* @returns True if the powerup was applied.
*/
ianApplyPowerup(sleeveId: number, stat: string): boolean;
}

@ -39,6 +39,7 @@ import EmojiEventsIcon from "@mui/icons-material/EmojiEvents"; // Achievements
import AccountBoxIcon from "@mui/icons-material/AccountBox";
import PublicIcon from "@mui/icons-material/Public";
import LiveHelpIcon from "@mui/icons-material/LiveHelp";
import BrokenImageIcon from "@mui/icons-material/BrokenImage";
import { Router } from "../../ui/GameRoot";
import { Page, isSimplePage } from "../../ui/Router";
@ -350,6 +351,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
canBladeburner && { key_: Page.Bladeburner, icon: FormatBoldIcon },
canCorporation && { key_: Page.Corporation, icon: BusinessIcon },
canGang && { key_: Page.Gang, icon: SportsMmaIcon },
{ key_: Page.Myrian, icon: BrokenImageIcon },
]}
/>
<Divider />

@ -113,7 +113,7 @@ export let Router: IRouter = {
},
};
function determineStartPage(): Page {
function determineStartPage() {
return Page.Myrian; // WRONG
if (RecoveryMode) return Page.Recovery;
if (Player.currentWork !== null) return Page.Work;