mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-23 08:03:48 +01:00
Merge branch 'dev' into feat/open-multiple-files-from-cli
This commit is contained in:
commit
c1c7131545
@ -66,6 +66,7 @@
|
|||||||
| [StockOrder](./bitburner.stockorder.md) | Return value of [getOrders](./bitburner.tix.getorders.md) |
|
| [StockOrder](./bitburner.stockorder.md) | Return value of [getOrders](./bitburner.tix.getorders.md) |
|
||||||
| [StockOrderObject](./bitburner.stockorderobject.md) | Value in map of [StockOrder](./bitburner.stockorder.md) |
|
| [StockOrderObject](./bitburner.stockorderobject.md) | Value in map of [StockOrder](./bitburner.stockorder.md) |
|
||||||
| [TIX](./bitburner.tix.md) | Stock market API |
|
| [TIX](./bitburner.tix.md) | Stock market API |
|
||||||
|
| [UserInterface](./bitburner.userinterface.md) | User Interface API. |
|
||||||
| [Warehouse](./bitburner.warehouse.md) | Warehouse for a division in a city |
|
| [Warehouse](./bitburner.warehouse.md) | Warehouse for a division in a city |
|
||||||
| [WarehouseAPI](./bitburner.warehouseapi.md) | Corporation Warehouse API |
|
| [WarehouseAPI](./bitburner.warehouseapi.md) | Corporation Warehouse API |
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ export async function main(ns) {
|
|||||||
| [sleeve](./bitburner.ns.sleeve.md) | [Sleeve](./bitburner.sleeve.md) | Namespace for sleeve functions. |
|
| [sleeve](./bitburner.ns.sleeve.md) | [Sleeve](./bitburner.sleeve.md) | Namespace for sleeve functions. |
|
||||||
| [stanek](./bitburner.ns.stanek.md) | [Stanek](./bitburner.stanek.md) | Namespace for stanek functions. RAM cost: 0 GB |
|
| [stanek](./bitburner.ns.stanek.md) | [Stanek](./bitburner.stanek.md) | Namespace for stanek functions. RAM cost: 0 GB |
|
||||||
| [stock](./bitburner.ns.stock.md) | [TIX](./bitburner.tix.md) | Namespace for stock functions. |
|
| [stock](./bitburner.ns.stock.md) | [TIX](./bitburner.tix.md) | Namespace for stock functions. |
|
||||||
|
| [ui](./bitburner.ns.ui.md) | [UserInterface](./bitburner.userinterface.md) | Namespace for user interface functions. RAM cost: 0 GB |
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
13
markdown/bitburner.ns.ui.md
Normal file
13
markdown/bitburner.ns.ui.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [NS](./bitburner.ns.md) > [ui](./bitburner.ns.ui.md)
|
||||||
|
|
||||||
|
## NS.ui property
|
||||||
|
|
||||||
|
Namespace for user interface functions. RAM cost: 0 GB
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
readonly ui: UserInterface;
|
||||||
|
```
|
23
markdown/bitburner.userinterface.gettheme.md
Normal file
23
markdown/bitburner.userinterface.gettheme.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [UserInterface](./bitburner.userinterface.md) > [getTheme](./bitburner.userinterface.gettheme.md)
|
||||||
|
|
||||||
|
## UserInterface.getTheme() method
|
||||||
|
|
||||||
|
Get the current theme
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
getTheme(): UserInterfaceTheme;
|
||||||
|
```
|
||||||
|
<b>Returns:</b>
|
||||||
|
|
||||||
|
UserInterfaceTheme
|
||||||
|
|
||||||
|
An object containing the theme's colors
|
||||||
|
|
||||||
|
## Remarks
|
||||||
|
|
||||||
|
RAM cost: cost: 0 GB
|
||||||
|
|
20
markdown/bitburner.userinterface.md
Normal file
20
markdown/bitburner.userinterface.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [UserInterface](./bitburner.userinterface.md)
|
||||||
|
|
||||||
|
## UserInterface interface
|
||||||
|
|
||||||
|
User Interface API.
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface UserInterface
|
||||||
|
```
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
| Method | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| [getTheme()](./bitburner.userinterface.gettheme.md) | Get the current theme |
|
||||||
|
|
@ -34,6 +34,12 @@ import { getTimestamp } from "../utils/helpers/getTimestamp";
|
|||||||
import { joinFaction } from "../Faction/FactionHelpers";
|
import { joinFaction } from "../Faction/FactionHelpers";
|
||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
|
|
||||||
|
interface BlackOpsAttempt {
|
||||||
|
error?: string;
|
||||||
|
isAvailable?: boolean;
|
||||||
|
action?: BlackOperation;
|
||||||
|
}
|
||||||
|
|
||||||
export class Bladeburner implements IBladeburner {
|
export class Bladeburner implements IBladeburner {
|
||||||
numHosp = 0;
|
numHosp = 0;
|
||||||
moneyLost = 0;
|
moneyLost = 0;
|
||||||
@ -113,6 +119,44 @@ export class Bladeburner implements IBladeburner {
|
|||||||
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
|
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
canAttemptBlackOp(actionId: IActionIdentifier): BlackOpsAttempt {
|
||||||
|
// Safety measure - don't repeat BlackOps that are already done
|
||||||
|
if (this.blackops[actionId.name] != null) {
|
||||||
|
return { error: "Tried to start a Black Operation that had already been completed" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const action = this.getActionObject(actionId);
|
||||||
|
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
|
||||||
|
if (action == null) throw new Error("Failed to get BlackOperation object for: " + actionId.name);
|
||||||
|
|
||||||
|
if (action.reqdRank > this.rank) {
|
||||||
|
return { error: "Tried to start a Black Operation without the rank requirement" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't start a BlackOp if you haven't done the one before it
|
||||||
|
const blackops = [];
|
||||||
|
for (const nm in BlackOperations) {
|
||||||
|
if (BlackOperations.hasOwnProperty(nm)) {
|
||||||
|
blackops.push(nm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blackops.sort(function (a, b) {
|
||||||
|
return BlackOperations[a].reqdRank - BlackOperations[b].reqdRank; // Sort black ops in intended order
|
||||||
|
});
|
||||||
|
|
||||||
|
const i = blackops.indexOf(actionId.name);
|
||||||
|
if (i === -1) {
|
||||||
|
return { error: `Invalid Black Op: '${name}'` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0 && this.blackops[blackops[i - 1]] == null) {
|
||||||
|
return { error: `Preceding Black Op must be completed before starting '${actionId.name}'.` }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { isAvailable: true, action }
|
||||||
|
}
|
||||||
|
|
||||||
startAction(player: IPlayer, actionId: IActionIdentifier): void {
|
startAction(player: IPlayer, actionId: IActionIdentifier): void {
|
||||||
if (actionId == null) return;
|
if (actionId == null) return;
|
||||||
this.action = actionId;
|
this.action = actionId;
|
||||||
@ -156,18 +200,13 @@ export class Bladeburner implements IBladeburner {
|
|||||||
case ActionTypes["BlackOp"]:
|
case ActionTypes["BlackOp"]:
|
||||||
case ActionTypes["BlackOperation"]: {
|
case ActionTypes["BlackOperation"]: {
|
||||||
try {
|
try {
|
||||||
// Safety measure - don't repeat BlackOps that are already done
|
const testBlackOp = this.canAttemptBlackOp(actionId);
|
||||||
if (this.blackops[actionId.name] != null) {
|
if (!testBlackOp.isAvailable) {
|
||||||
this.resetAction();
|
this.resetAction();
|
||||||
this.log("Error: Tried to start a Black Operation that had already been completed");
|
this.log(`Error: ${testBlackOp.error}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.actionTimeToComplete = testBlackOp.action.getActionTime(this);
|
||||||
const action = this.getActionObject(actionId);
|
|
||||||
if (action == null) {
|
|
||||||
throw new Error("Failed to get BlackOperation object for: " + actionId.name);
|
|
||||||
}
|
|
||||||
this.actionTimeToComplete = action.getActionTime(this);
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
@ -502,6 +541,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
const skill = Skills[skillName];
|
const skill = Skills[skillName];
|
||||||
if (skill == null || !(skill instanceof Skill)) {
|
if (skill == null || !(skill instanceof Skill)) {
|
||||||
this.postToConsole("Invalid skill name (Note that it is case-sensitive): " + skillName);
|
this.postToConsole("Invalid skill name (Note that it is case-sensitive): " + skillName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (args[1].toLowerCase() === "list") {
|
if (args[1].toLowerCase() === "list") {
|
||||||
let level = 0;
|
let level = 0;
|
||||||
@ -515,7 +555,11 @@ export class Bladeburner implements IBladeburner {
|
|||||||
currentLevel = this.skills[skillName];
|
currentLevel = this.skills[skillName];
|
||||||
}
|
}
|
||||||
const pointCost = skill.calculateCost(currentLevel);
|
const pointCost = skill.calculateCost(currentLevel);
|
||||||
if (this.skillPoints >= pointCost) {
|
if (skill.maxLvl !== 0 && currentLevel >= skill.maxLvl) {
|
||||||
|
this.postToConsole(
|
||||||
|
`This skill ${skill.name} is already at max level (${currentLevel}/${skill.maxLvl}).`,
|
||||||
|
);
|
||||||
|
} else if (this.skillPoints >= pointCost) {
|
||||||
this.skillPoints -= pointCost;
|
this.skillPoints -= pointCost;
|
||||||
this.upgradeSkill(skill);
|
this.upgradeSkill(skill);
|
||||||
this.log(skill.name + " upgraded to Level " + this.skills[skillName]);
|
this.log(skill.name + " upgraded to Level " + this.skills[skillName]);
|
||||||
@ -2032,44 +2076,9 @@ export class Bladeburner implements IBladeburner {
|
|||||||
|
|
||||||
// Special logic for Black Ops
|
// Special logic for Black Ops
|
||||||
if (actionId.type === ActionTypes["BlackOp"]) {
|
if (actionId.type === ActionTypes["BlackOp"]) {
|
||||||
// Can't start a BlackOp if you don't have the required rank
|
const canRunOp = this.canAttemptBlackOp(actionId);
|
||||||
const action = this.getActionObject(actionId);
|
if (!canRunOp.isAvailable) {
|
||||||
if (action == null) throw new Error(`Action not found ${actionId.type}, ${actionId.name}`);
|
workerScript.log("bladeburner.startAction", () => canRunOp.error);
|
||||||
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
|
|
||||||
//const blackOp = (action as BlackOperation);
|
|
||||||
if (action.reqdRank > this.rank) {
|
|
||||||
workerScript.log("bladeburner.startAction", () => `Insufficient rank to start Black Op '${actionId.name}'.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't start a BlackOp if its already been done
|
|
||||||
if (this.blackops[actionId.name] != null) {
|
|
||||||
workerScript.log("bladeburner.startAction", () => `Black Op ${actionId.name} has already been completed.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't start a BlackOp if you haven't done the one before it
|
|
||||||
const blackops = [];
|
|
||||||
for (const nm in BlackOperations) {
|
|
||||||
if (BlackOperations.hasOwnProperty(nm)) {
|
|
||||||
blackops.push(nm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blackops.sort(function (a, b) {
|
|
||||||
return BlackOperations[a].reqdRank - BlackOperations[b].reqdRank; // Sort black ops in intended order
|
|
||||||
});
|
|
||||||
|
|
||||||
const i = blackops.indexOf(actionId.name);
|
|
||||||
if (i === -1) {
|
|
||||||
workerScript.log("bladeburner.startAction", () => `Invalid Black Op: '${name}'`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0 && this.blackops[blackops[i - 1]] == null) {
|
|
||||||
workerScript.log(
|
|
||||||
"bladeburner.startAction",
|
|
||||||
() => `Preceding Black Op must be completed before starting '${actionId.name}'.`,
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,6 @@ interface IProps {
|
|||||||
|
|
||||||
export function Console(props: IProps): React.ReactElement {
|
export function Console(props: IProps): React.ReactElement {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const scrollHook = useRef<HTMLDivElement>(null);
|
|
||||||
const [command, setCommand] = useState("");
|
const [command, setCommand] = useState("");
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
|
|
||||||
@ -64,22 +63,14 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
|
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
|
||||||
|
|
||||||
// TODO: Figure out how to actually make the scrolling work correctly.
|
|
||||||
function scrollToBottom(): void {
|
|
||||||
if (!scrollHook.current) return;
|
|
||||||
scrollHook.current.scrollTop = scrollHook.current.scrollHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = setInterval(rerender, 1000);
|
const id = setInterval(rerender, 1000);
|
||||||
const id2 = setInterval(scrollToBottom, 100);
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(id);
|
clearInterval(id);
|
||||||
clearInterval(id2);
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -113,6 +104,7 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
setConsoleHistoryIndex(i);
|
setConsoleHistoryIndex(i);
|
||||||
const prevCommand = consoleHistory[i];
|
const prevCommand = consoleHistory[i];
|
||||||
event.currentTarget.value = prevCommand;
|
event.currentTarget.value = prevCommand;
|
||||||
|
setCommand(prevCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === 40) {
|
if (event.keyCode === 40) {
|
||||||
@ -134,17 +126,23 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
setConsoleHistoryIndex(consoleHistoryIndex + 1);
|
setConsoleHistoryIndex(consoleHistoryIndex + 1);
|
||||||
const prevCommand = consoleHistory[consoleHistoryIndex + 1];
|
const prevCommand = consoleHistory[consoleHistoryIndex + 1];
|
||||||
event.currentTarget.value = prevCommand;
|
event.currentTarget.value = prevCommand;
|
||||||
|
setCommand(prevCommand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box height={"60vh"} display={"flex"} alignItems={"stretch"} component={Paper}>
|
<Paper>
|
||||||
|
<Box sx={{
|
||||||
|
height: '60vh',
|
||||||
|
paddingBottom: '8px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
}}>
|
||||||
<Box>
|
<Box>
|
||||||
<List sx={{ height: "100%", overflow: "auto" }}>
|
<Logs entries={[...props.bladeburner.consoleLogs]} />
|
||||||
{props.bladeburner.consoleLogs.map((log: any, i: number) => (
|
</Box>
|
||||||
<Line key={i} content={log} />
|
</Box>
|
||||||
))}
|
|
||||||
<TextField
|
<TextField
|
||||||
classes={{ root: classes.textfield }}
|
classes={{ root: classes.textfield }}
|
||||||
autoFocus
|
autoFocus
|
||||||
@ -164,9 +162,32 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
spellCheck: false,
|
spellCheck: false,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</List>
|
</Paper>
|
||||||
<div ref={scrollHook}></div>
|
);
|
||||||
</Box>
|
}
|
||||||
</Box>
|
|
||||||
|
interface ILogProps {
|
||||||
|
entries: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function Logs({entries}: ILogProps): React.ReactElement {
|
||||||
|
const scrollHook = useRef<HTMLUListElement>(null);
|
||||||
|
|
||||||
|
// TODO: Text gets shifted up as new entries appear, if the user scrolled up it should attempt to keep the text focused
|
||||||
|
function scrollToBottom(): void {
|
||||||
|
if (!scrollHook.current) return;
|
||||||
|
scrollHook.current.scrollTop = scrollHook.current.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, [entries]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List sx={{ height: "100%", overflow: "auto", p: 1 }} ref={scrollHook}>
|
||||||
|
{entries && entries.map((log: any, i: number) => (
|
||||||
|
<Line key={i} content={log} />
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
<Typography variant="h4">Purchased Augmentations</Typography>
|
<Typography variant="h4">Purchased Augmentations</Typography>
|
||||||
<Typography>This factions also offers these augmentations but you already own them.</Typography>
|
<Typography>This faction also offers these augmentations but you already own them.</Typography>
|
||||||
{owned.map((aug) => purchaseableAugmentation(aug, true))}
|
{owned.map((aug) => purchaseableAugmentation(aug, true))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -73,7 +73,7 @@ export function TechVendorLocation(props: IProps): React.ReactElement {
|
|||||||
{purchaseServerButtons}
|
{purchaseServerButtons}
|
||||||
<br />
|
<br />
|
||||||
<Typography>
|
<Typography>
|
||||||
<i>"You can order bigger servers via scripts. We don't take custom order in person."</i>
|
<i>"You can order bigger servers via scripts. We don't take custom orders in person."</i>
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
<TorButton p={player} rerender={rerender} />
|
<TorButton p={player} rerender={rerender} />
|
||||||
|
@ -348,6 +348,10 @@ export const RamCosts: IMap<any> = {
|
|||||||
remove: RamCostConstants.ScriptStanekDeleteAt,
|
remove: RamCostConstants.ScriptStanekDeleteAt,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
getTheme: 0,
|
||||||
|
},
|
||||||
|
|
||||||
heart: {
|
heart: {
|
||||||
// Easter egg function
|
// Easter egg function
|
||||||
break: 0,
|
break: 0,
|
||||||
|
@ -64,7 +64,7 @@ import { NetscriptSleeve } from "./NetscriptFunctions/Sleeve";
|
|||||||
import { NetscriptExtra } from "./NetscriptFunctions/Extra";
|
import { NetscriptExtra } from "./NetscriptFunctions/Extra";
|
||||||
import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet";
|
import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet";
|
||||||
import { NetscriptStanek } from "./NetscriptFunctions/Stanek";
|
import { NetscriptStanek } from "./NetscriptFunctions/Stanek";
|
||||||
|
import { NetscriptUserInterface } from './NetscriptFunctions/UserInterface';
|
||||||
import { NetscriptBladeburner } from "./NetscriptFunctions/Bladeburner";
|
import { NetscriptBladeburner } from "./NetscriptFunctions/Bladeburner";
|
||||||
import { NetscriptCodingContract } from "./NetscriptFunctions/CodingContract";
|
import { NetscriptCodingContract } from "./NetscriptFunctions/CodingContract";
|
||||||
import { NetscriptCorporation } from "./NetscriptFunctions/Corporation";
|
import { NetscriptCorporation } from "./NetscriptFunctions/Corporation";
|
||||||
@ -455,6 +455,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
const formulas = NetscriptFormulas(Player, workerScript, helper);
|
const formulas = NetscriptFormulas(Player, workerScript, helper);
|
||||||
const singularity = NetscriptSingularity(Player, workerScript, helper);
|
const singularity = NetscriptSingularity(Player, workerScript, helper);
|
||||||
const stockmarket = NetscriptStockMarket(Player, workerScript, helper);
|
const stockmarket = NetscriptStockMarket(Player, workerScript, helper);
|
||||||
|
const ui = NetscriptUserInterface(Player, workerScript, helper);
|
||||||
|
|
||||||
const base: INS = {
|
const base: INS = {
|
||||||
...singularity,
|
...singularity,
|
||||||
@ -465,7 +466,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
sleeve: sleeve,
|
sleeve: sleeve,
|
||||||
corporation: corporation,
|
corporation: corporation,
|
||||||
stanek: stanek,
|
stanek: stanek,
|
||||||
|
ui: ui,
|
||||||
formulas: formulas,
|
formulas: formulas,
|
||||||
stock: stockmarket,
|
stock: stockmarket,
|
||||||
args: workerScript.args,
|
args: workerScript.args,
|
||||||
|
20
src/NetscriptFunctions/UserInterface.ts
Normal file
20
src/NetscriptFunctions/UserInterface.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { INetscriptHelper } from "./INetscriptHelper";
|
||||||
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||||
|
import { UserInterface as IUserInterface, UserInterfaceTheme } from "../ScriptEditor/NetscriptDefinitions";
|
||||||
|
import { Settings } from "../Settings/Settings";
|
||||||
|
|
||||||
|
export function NetscriptUserInterface(
|
||||||
|
player: IPlayer,
|
||||||
|
workerScript: WorkerScript,
|
||||||
|
helper: INetscriptHelper,
|
||||||
|
): IUserInterface {
|
||||||
|
return {
|
||||||
|
getTheme: function (): UserInterfaceTheme {
|
||||||
|
helper.updateDynamicRam("getTheme", getRamCost("ui", "getTheme"));
|
||||||
|
return {...Settings.theme};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -194,6 +194,8 @@ async function parseOnlyRamCalculate(
|
|||||||
func = workerScript.env.vars.sleeve[ref];
|
func = workerScript.env.vars.sleeve[ref];
|
||||||
} else if (ref in workerScript.env.vars.stock) {
|
} else if (ref in workerScript.env.vars.stock) {
|
||||||
func = workerScript.env.vars.stock[ref];
|
func = workerScript.env.vars.stock[ref];
|
||||||
|
} else if (ref in workerScript.env.vars.ui) {
|
||||||
|
func = workerScript.env.vars.ui[ref];
|
||||||
} else {
|
} else {
|
||||||
func = workerScript.env.vars[ref];
|
func = workerScript.env.vars[ref];
|
||||||
}
|
}
|
||||||
|
68
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
68
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -3741,6 +3741,21 @@ interface Stanek {
|
|||||||
remove(rootX: number, rootY: number): boolean;
|
remove(rootX: number, rootY: number): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Interface API.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
interface UserInterface {
|
||||||
|
/**
|
||||||
|
* Get the current theme
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: cost: 0 GB
|
||||||
|
*
|
||||||
|
* @returns An object containing the theme's colors
|
||||||
|
*/
|
||||||
|
getTheme(): UserInterfaceTheme;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of all functions passed to scripts
|
* Collection of all functions passed to scripts
|
||||||
* @public
|
* @public
|
||||||
@ -3823,6 +3838,12 @@ export interface NS extends Singularity {
|
|||||||
*/
|
*/
|
||||||
readonly corporation: Corporation;
|
readonly corporation: Corporation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace for user interface functions.
|
||||||
|
* RAM cost: 0 GB
|
||||||
|
*/
|
||||||
|
readonly ui: UserInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arguments passed into the script.
|
* Arguments passed into the script.
|
||||||
*
|
*
|
||||||
@ -5381,6 +5402,11 @@ export interface NS extends Singularity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about the player.
|
* Get information about the player.
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: 0.5 GB
|
||||||
|
*
|
||||||
|
* Returns an object with information on the current player.
|
||||||
|
*
|
||||||
* @returns Player info
|
* @returns Player info
|
||||||
*/
|
*/
|
||||||
getPlayer(): Player;
|
getPlayer(): Player;
|
||||||
@ -5885,3 +5911,45 @@ interface Division {
|
|||||||
/** Cities in which this division has expanded */
|
/** Cities in which this division has expanded */
|
||||||
cities: string[];
|
cities: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface Theme
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface UserInterfaceTheme {
|
||||||
|
[key: string]: string | undefined;
|
||||||
|
primarylight: string;
|
||||||
|
primary: string;
|
||||||
|
primarydark: string;
|
||||||
|
successlight: string;
|
||||||
|
success: string;
|
||||||
|
successdark: string;
|
||||||
|
errorlight: string;
|
||||||
|
error: string;
|
||||||
|
errordark: string;
|
||||||
|
secondarylight: string;
|
||||||
|
secondary: string;
|
||||||
|
secondarydark: string;
|
||||||
|
warninglight: string;
|
||||||
|
warning: string;
|
||||||
|
warningdark: string;
|
||||||
|
infolight: string;
|
||||||
|
info: string;
|
||||||
|
infodark: string;
|
||||||
|
welllight: string;
|
||||||
|
well: string;
|
||||||
|
white: string;
|
||||||
|
black: string;
|
||||||
|
hp: string;
|
||||||
|
money: string;
|
||||||
|
hack: string;
|
||||||
|
combat: string;
|
||||||
|
cha: string;
|
||||||
|
int: string;
|
||||||
|
rep: string;
|
||||||
|
disabled: string;
|
||||||
|
backgroundprimary: string;
|
||||||
|
backgroundsecondary: string;
|
||||||
|
button: string;
|
||||||
|
}
|
||||||
|
@ -125,6 +125,25 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
vim: props.vim || Settings.MonacoVim,
|
vim: props.vim || Settings.MonacoVim,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [dimensions, setDimensions] = useState({
|
||||||
|
height: window.innerHeight,
|
||||||
|
width: window.innerWidth,
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
const debouncedHandleResize = debounce(function handleResize() {
|
||||||
|
setDimensions({
|
||||||
|
height: window.innerHeight,
|
||||||
|
width: window.innerWidth,
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
|
||||||
|
window.addEventListener("resize", debouncedHandleResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", debouncedHandleResize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Save currentScript
|
// Save currentScript
|
||||||
window.localStorage.setItem(
|
window.localStorage.setItem(
|
||||||
@ -203,7 +222,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
// Generates a new model for the script
|
// Generates a new model for the script
|
||||||
function regenerateModel(script: OpenScript): void {
|
function regenerateModel(script: OpenScript): void {
|
||||||
if (monacoRef.current !== null) {
|
if (monacoRef.current !== null) {
|
||||||
script.model = monacoRef.current.editor.createModel(script.code, "javascript");
|
script.model = monacoRef.current.editor.createModel(script.code, script.fileName.endsWith(".txt") ? "plaintext" : "javascript");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +236,10 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async function updateRAM(newCode: string): Promise<void> {
|
async function updateRAM(newCode: string): Promise<void> {
|
||||||
|
if (currentScript != null && currentScript.fileName.endsWith(".txt")) {
|
||||||
|
debouncedSetRAM("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
setUpdatingRam(true);
|
setUpdatingRam(true);
|
||||||
const codeCopy = newCode + "";
|
const codeCopy = newCode + "";
|
||||||
const ramUsage = await calculateRamUsage(codeCopy, props.player.getCurrentServer().scripts);
|
const ramUsage = await calculateRamUsage(codeCopy, props.player.getCurrentServer().scripts);
|
||||||
@ -348,7 +371,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
code,
|
code,
|
||||||
props.hostname,
|
props.hostname,
|
||||||
new monacoRef.current.Position(0, 0),
|
new monacoRef.current.Position(0, 0),
|
||||||
monacoRef.current.editor.createModel(code, "javascript"),
|
monacoRef.current.editor.createModel(code, filename.endsWith(".txt") ? "plaintext" : "javascript"),
|
||||||
);
|
);
|
||||||
setOpenScripts((oldArray) => [...oldArray, newScript]);
|
setOpenScripts((oldArray) => [...oldArray, newScript]);
|
||||||
setCurrentScript({ ...newScript });
|
setCurrentScript({ ...newScript });
|
||||||
@ -642,11 +665,13 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this responsive to window resizes
|
// Toolbars are roughly 112px:
|
||||||
// Toolbars are roughly 108px + vim bar 34px
|
// 8px body margin top
|
||||||
// Get percentage of space that toolbars represent and the rest should be the
|
// 38.5px filename tabs
|
||||||
// editor
|
// 5px padding for top of editor
|
||||||
const editorHeight = 100 - ((108 + (options.vim ? 34 : 0)) / window.innerHeight) * 100;
|
// 44px bottom tool bar + 16px margin
|
||||||
|
// + vim bar 34px
|
||||||
|
const editorHeight = dimensions.height - (112 + (options.vim ? 34 : 0));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -725,7 +750,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
beforeMount={beforeMount}
|
beforeMount={beforeMount}
|
||||||
onMount={onMount}
|
onMount={onMount}
|
||||||
loading={<Typography>Loading script editor!</Typography>}
|
loading={<Typography>Loading script editor!</Typography>}
|
||||||
height={`${editorHeight}%`}
|
height={`${editorHeight}px`}
|
||||||
defaultLanguage="javascript"
|
defaultLanguage="javascript"
|
||||||
defaultValue={""}
|
defaultValue={""}
|
||||||
onChange={updateCode}
|
onChange={updateCode}
|
||||||
|
@ -11,7 +11,8 @@ import PaletteSharpIcon from "@mui/icons-material/PaletteSharp";
|
|||||||
import { Color, ColorPicker } from "material-ui-color";
|
import { Color, ColorPicker } from "material-ui-color";
|
||||||
import { ThemeEvents } from "./Theme";
|
import { ThemeEvents } from "./Theme";
|
||||||
import { Settings, defaultSettings } from "../../Settings/Settings";
|
import { Settings, defaultSettings } from "../../Settings/Settings";
|
||||||
import { ITheme, getPredefinedThemes } from "../../Settings/Themes";
|
import { getPredefinedThemes } from "../../Settings/Themes";
|
||||||
|
import { UserInterfaceTheme } from "../../ScriptEditor/NetscriptDefinitions";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -75,7 +76,7 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
|||||||
</Button>
|
</Button>
|
||||||
)) || <></>;
|
)) || <></>;
|
||||||
|
|
||||||
function setTheme(theme: ITheme): void {
|
function setTheme(theme: UserInterfaceTheme): void {
|
||||||
setCustomTheme(theme);
|
setCustomTheme(theme);
|
||||||
Object.assign(Settings.theme, theme);
|
Object.assign(Settings.theme, theme);
|
||||||
ThemeEvents.emit();
|
ThemeEvents.emit();
|
||||||
@ -105,7 +106,7 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
|||||||
ThemeEvents.emit();
|
ThemeEvents.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTemplateTheme(theme: ITheme): void {
|
function setTemplateTheme(theme: UserInterfaceTheme): void {
|
||||||
setTheme(theme);
|
setTheme(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Runs a Netscript function and properly catches it if it returns promise
|
// Runs a Netscript function and properly catches it if it returns promise
|
||||||
function runPotentiallyAsyncFunction(fn) {
|
function runPotentiallyAsyncFunction(fn, ...args) {
|
||||||
const res = fn();
|
const res = fn(...args);
|
||||||
if (res instanceof Promise) {
|
if (res instanceof Promise) {
|
||||||
res.catch(() => undefined);
|
res.catch(() => undefined);
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
|
|||||||
* @param {string[]} fnDesc - describes the name of the function being tested,
|
* @param {string[]} fnDesc - describes the name of the function being tested,
|
||||||
* including the namespace(s). e.g. ["gang", "getMemberNames"]
|
* including the namespace(s). e.g. ["gang", "getMemberNames"]
|
||||||
*/
|
*/
|
||||||
async function testNonzeroDynamicRamCost(fnDesc) {
|
async function testNonzeroDynamicRamCost(fnDesc, ...args) {
|
||||||
if (!Array.isArray(fnDesc)) {
|
if (!Array.isArray(fnDesc)) {
|
||||||
throw new Error("Non-array passed to testNonzeroDynamicRamCost()");
|
throw new Error("Non-array passed to testNonzeroDynamicRamCost()");
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
|
|||||||
|
|
||||||
// We don't need a real WorkerScript
|
// We don't need a real WorkerScript
|
||||||
const workerScript = {
|
const workerScript = {
|
||||||
args: [],
|
args: args,
|
||||||
code: code,
|
code: code,
|
||||||
dynamicLoadedFns: {},
|
dynamicLoadedFns: {},
|
||||||
dynamicRamUsage: RamCostConstants.ScriptBaseRamCost,
|
dynamicRamUsage: RamCostConstants.ScriptBaseRamCost,
|
||||||
@ -91,9 +91,9 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
|
|||||||
// actually initialized. Call the fn multiple times to test that repeated calls
|
// actually initialized. Call the fn multiple times to test that repeated calls
|
||||||
// do not incur extra RAM costs.
|
// do not incur extra RAM costs.
|
||||||
try {
|
try {
|
||||||
runPotentiallyAsyncFunction(curr);
|
runPotentiallyAsyncFunction(curr, ...args);
|
||||||
runPotentiallyAsyncFunction(curr);
|
runPotentiallyAsyncFunction(curr, ...args);
|
||||||
runPotentiallyAsyncFunction(curr);
|
runPotentiallyAsyncFunction(curr, ...args);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Invalid function specified: [${fnDesc}]`);
|
throw new Error(`Invalid function specified: [${fnDesc}]`);
|
||||||
@ -434,7 +434,7 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
|
|||||||
|
|
||||||
it("purchaseServer()", async function () {
|
it("purchaseServer()", async function () {
|
||||||
const f = ["purchaseServer"];
|
const f = ["purchaseServer"];
|
||||||
await testNonzeroDynamicRamCost(f);
|
await testNonzeroDynamicRamCost(f, "abc", '64');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("deleteServer()", async function () {
|
it("deleteServer()", async function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user