Merge branch 'dev' into bugfix/2958

This commit is contained in:
Jack
2022-03-30 08:26:18 +08:00
committed by GitHub
336 changed files with 7898 additions and 156491 deletions
+193 -31
View File
@@ -94,6 +94,8 @@ interface Player {
factions: string[];
tor: boolean;
hasCorporation: boolean;
inBladeburner: boolean;
entropy: number;
}
/**
@@ -665,6 +667,10 @@ export interface CharacterMult {
agility: number;
/** Agility exp */
agilityExp: number;
/** Charisma stat */
charisma: number;
/** Charisma exp */
charismaExp: number;
/** Company reputation */
companyRep: number;
/** Money earned from crimes */
@@ -705,10 +711,10 @@ export interface CharacterInfo {
factions: string[];
/** Current health points */
hp: number;
/** Array of all companies at which you have jobs */
company: string[];
/** Array of all jobs */
jobs: string[];
/** Array of job positions for all companies you are employed at. Same order as 'jobs' */
jobTitle: string[];
jobTitles: string[];
/** Maximum health points */
maxHp: number;
/** Boolean indicating whether or not you have a tor router */
@@ -733,6 +739,18 @@ export interface CharacterInfo {
workRepGain: number;
/** Money earned so far from work, if applicable */
workMoneyGain: number;
/** total hacking exp */
hackingExp: number;
/** total strength exp */
strengthExp: number;
/** total defense exp */
defenseExp: number;
/** total dexterity exp */
dexterityExp: number;
/** total agility exp */
agilityExp: number;
/** total charisma exp */
charismaExp: number;
}
/**
@@ -1505,6 +1523,20 @@ export interface TIX {
* @returns True if you successfully purchased it or if you already have access, false otherwise.
*/
purchase4SMarketDataTixApi(): boolean;
/**
* Purchase WSE Account.
* @remarks RAM cost: 2.5 GB
* @returns True if you successfully purchased it or if you already have access, false otherwise.
*/
purchaseWseAccount(): boolean;
/**
* Purchase TIX API Access
* @remarks RAM cost: 2.5 GB
* @returns True if you successfully purchased it or if you already have access, false otherwise.
*/
purchaseTixApi(): boolean;
}
/**
@@ -1582,7 +1614,7 @@ export interface Singularity {
* purchasing a TOR router using this function is the same as if you were to
* manually purchase one.
*
* @returns True if actions is successful, false otherwise.
* @returns True if actions is successful or you already own TOR router, false otherwise.
*/
purchaseTor(): boolean;
@@ -2183,11 +2215,8 @@ export interface Singularity {
* Hospitalize the player.
* @remarks
* RAM cost: 0.25 GB * 16/4/1
*
*
* @returns The cost of the hospitalization.
*/
hospitalize(): number;
hospitalize(): void;
/**
* Soft reset the game.
@@ -2274,6 +2303,67 @@ export interface Singularity {
* @returns True if the focus was changed.
*/
setFocus(focus: boolean): boolean;
/**
* Get a list of programs offered on the dark web.
* @remarks
* RAM cost: 1 GB * 16/4/1
*
*
* This function allows the player to get a list of programs available for purchase
* on the dark web. Players MUST have purchased Tor to get the list of programs
* available. If Tor has not been purchased yet, this function will return an
* empty list.
*
* @example
* ```ts
* // NS1
* getDarkwebProgramsAvailable();
* // returns ['BruteSSH.exe', 'FTPCrack.exe'...etc]
* ```
* @example
* ```ts
* // NS2
* ns.getDarkwebProgramsAvailable();
* // returns ['BruteSSH.exe', 'FTPCrack.exe'...etc]
* ```
* @returns - a list of programs available for purchase on the dark web, or [] if Tor has not
* been purchased
*/
getDarkwebPrograms(): string[];
/**
* Check the price of an exploit on the dark web
* @remarks
* RAM cost: 0.5 GB * 16/4/1
*
*
* This function allows you to check the price of a darkweb exploit/program.
* You MUST have a TOR router in order to use this function. The price returned
* by this function is the same price you would see with buy -l from the terminal.
* Returns the cost of the program if it has not been purchased yet, 0 if it
* has already been purchased, or -1 if Tor has not been purchased (and thus
* the program/exploit is not available for purchase).
*
* If the program does not exist, an error is thrown.
*
*
* @example
* ```ts
* // NS1
* getDarkwebProgramCost("brutessh.exe");
* ```
* @example
* ```ts
* // NS2
* ns.getDarkwebProgramCost("brutessh.exe");
* ```
* @param programName - Name of program to check the price of
* @returns Price of the specified darkweb program
* (if not yet purchased), 0 if it has already been purchased, or -1 if Tor has not been
* purchased. Throws an error if the specified program/exploit does not exist
*/
getDarkwebProgramCost(programName: string): number;
}
/**
@@ -2784,7 +2874,7 @@ export interface Bladeburner {
*
* Note that this is meant to be used for Contracts and Operations.
* This function will return Infinity for actions such as Training and Field Analysis.
* This function will return 1 for BlackOps not yet completed regardless of wether
* This function will return 1 for BlackOps not yet completed regardless of whether
* the player has the required rank to attempt the mission or not.
*
* @param type - Type of action.
@@ -2824,7 +2914,7 @@ export interface Bladeburner {
getActionCurrentLevel(type: string, name: string): number;
/**
* Get wether an action is set to autolevel.
* Get whether an action is set to autolevel.
* @remarks
* RAM cost: 4 GB
*
@@ -3643,6 +3733,49 @@ export interface Sleeve {
purchaseSleeveAug(sleeveNumber: number, augName: string): boolean;
}
/**
* Grafting API
* @remarks
* This API requires Source-File 10 to use.
* @public
*/
export interface Grafting {
/**
* Retrieve the grafting cost of an aug.
* @remarks
* RAM cost: 3.75 GB
*
* @param augName - Name of the aug to check the price of. Must be an exact match.
* @returns The cost required to graft the named augmentation.
* @throws Will error if an invalid Augmentation name is provided.
*/
getAugmentationGraftPrice(augName: string): number;
/**
* Retrieves the time required to graft an aug.
* @remarks
* RAM cost: 3.75 GB
*
* @param augName - Name of the aug to check the grafting time of. Must be an exact match.
* @returns The time required, in millis, to graft the named augmentation.
* @throws Will error if an invalid Augmentation name is provided.
*/
getAugmentationGraftTime(augName: string): number;
/**
* Begins grafting the named aug. You must be in New Tokyo to use this.
* @remarks
* RAM cost: 7.5 GB
*
* @param augName - The name of the aug to begin grafting. Must be an exact match.
* @param focus - Acquire player focus on this Augmentation grafting. Optional. Defaults to true.
* @returns True if the aug successfully began grafting, false otherwise (e.g. not enough money, or
* invalid Augmentation name provided).
* @throws Will error if called while you are not in New Tokyo.
*/
graftAugmentation(augName: string, focus?: boolean): boolean;
}
/**
* Skills formulas
* @public
@@ -3952,14 +4085,14 @@ interface Stanek {
* RAM cost: 0.4 GB
* @returns The width of the gift.
*/
width(): number;
giftWidth(): number;
/**
* Stanek's Gift height.
* @remarks
* RAM cost: 0.4 GB
* @returns The height of the gift.
*/
height(): number;
giftHeight(): number;
/**
* Charge a fragment, increasing its power.
@@ -3969,7 +4102,7 @@ interface Stanek {
* @param rootY - rootY Root Y against which to align the top left of the fragment.
* @returns Promise that lasts until the charge action is over.
*/
charge(rootX: number, rootY: number): Promise<void>;
chargeFragment(rootX: number, rootY: number): Promise<void>;
/**
* List possible fragments.
@@ -3994,7 +4127,7 @@ interface Stanek {
* @remarks
* RAM cost: 0 GB
*/
clear(): void;
clearGift(): void;
/**
* Check if fragment can be placed at specified location.
@@ -4007,7 +4140,7 @@ interface Stanek {
* @param fragmentId - fragmentId ID of the fragment to place.
* @returns true if the fragment can be placed at that position. false otherwise.
*/
canPlace(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
canPlaceFragment(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
/**
* Place fragment on Stanek's Gift.
* @remarks
@@ -4019,7 +4152,7 @@ interface Stanek {
* @param fragmentId - ID of the fragment to place.
* @returns true if the fragment can be placed at that position. false otherwise.
*/
place(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
placeFragment(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
/**
* Get placed fragment at location.
* @remarks
@@ -4029,7 +4162,7 @@ interface Stanek {
* @param rootY - Y against which to align the top left of the fragment.
* @returns The fragment at [rootX, rootY], if any.
*/
get(rootX: number, rootY: number): ActiveFragment | undefined;
getFragment(rootX: number, rootY: number): ActiveFragment | undefined;
/**
* Remove fragment at location.
@@ -4040,7 +4173,7 @@ interface Stanek {
* @param rootY - Y against which to align the top left of the fragment.
* @returns The fragment at [rootX, rootY], if any.
*/
remove(rootX: number, rootY: number): boolean;
removeFragment(rootX: number, rootY: number): boolean;
}
/**
@@ -4204,6 +4337,19 @@ export interface NS extends Singularity {
*/
readonly ui: UserInterface;
/**
* Namespace for singularity functions.
* RAM cost: 0 GB
*/
readonly singularity: Singularity;
/**
* Namespace for grafting functions.
* @remarks
* RAM cost: 0 GB
*/
readonly grafting: Grafting;
/**
* Arguments passed into the script.
*
@@ -5983,19 +6129,25 @@ export interface NS extends Singularity {
tFormat(milliseconds: number, milliPrecision?: boolean): string;
/**
* Prompt the player with a Yes/No modal.
* Prompt the player with an input modal.
* @remarks
* RAM cost: 0 GB
*
* Prompts the player with a dialog box with two options: “Yes” and “No”.
* This function will return true if the player click “Yes” and false if
* the player clicks “No”. The scripts execution is halted until the player
* selects one of the options.
* Prompts the player with a dialog box. If `options.type` is undefined or "boolean",
* the player is shown "Yes" and "No" prompts, which return true and false respectively.
* Passing a type of "text" will give the player a text field and a value of "select"
* will show a drop-down field. Choosing type "select" will require an array or object
* to be passed via the `options.choices` property.
* The scripts execution is halted until the player selects one of the options.
*
* @param txt - Text to appear in the prompt dialog box.
* @returns True if the player click “Yes” and false if the player clicks “No”.
* @param options - Options to modify the prompt the player is shown.
* @returns True if the player click “Yes”; false if the player clicks “No”; or the value entered by the player.
*/
prompt(txt: string): Promise<boolean>;
prompt(
txt: string,
options?: { type?: "boolean" | "text" | "select" | undefined; choices?: string[] },
): Promise<boolean | string>;
/**
* Open up a message box.
@@ -6385,12 +6537,12 @@ export interface WarehouseAPI {
*/
buyMaterial(divisionName: string, cityName: string, materialName: string, amt: number): void;
/**
* Set material to bulk buy
* @param divisionName - Name of the division
* @param cityName - Name of the city
* @param materialName - Name of the material
* @param amt - Amount of material to buy
*/
* Set material to bulk buy
* @param divisionName - Name of the division
* @param cityName - Name of the city
* @param materialName - Name of the material
* @param amt - Amount of material to buy
*/
bulkPurchase(divisionName: string, cityName: string, materialName: string, amt: number): void;
/**
* Get warehouse data
@@ -6644,6 +6796,16 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
*
*/
sellShares(amount: number): void;
/**
* Get bonus time.
*
* “Bonus time” is accumulated when the game is offline or if the game is inactive in the browser.
*
* “Bonus time” makes the game progress faster.
*
* @returns Bonus time for the Corporation mechanic in milliseconds.
*/
getBonusTime(): number;
}
/**
+33 -8
View File
@@ -17,6 +17,7 @@ import { calculateRamUsage, checkInfiniteLoop } from "../../Script/RamCalculatio
import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes";
import { numeralWrapper } from "../../ui/numeralFormat";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import SearchIcon from "@mui/icons-material/Search";
import { NetscriptFunctions } from "../../NetscriptFunctions";
import { WorkerScript } from "../../Netscript/WorkerScript";
@@ -42,7 +43,7 @@ import { PromptEvent } from "../../ui/React/PromptManager";
import { Modal } from "../../ui/React/Modal";
import libSource from "!!raw-loader!../NetscriptDefinitions.d.ts";
import { Tooltip } from "@mui/material";
import { TextField, Tooltip } from "@mui/material";
interface IProps {
// Map of filename -> code
@@ -113,6 +114,8 @@ export function Root(props: IProps): React.ReactElement {
const vimStatusRef = useRef<HTMLElement>(null);
const [vimEditor, setVimEditor] = useState<any>(null);
const [editor, setEditor] = useState<IStandaloneCodeEditor | null>(null);
const [filter, setFilter] = useState("");
const [searchExpanded, setSearchExpanded] = useState(false);
const [ram, setRAM] = useState("RAM: ???");
const [ramEntries, setRamEntries] = useState<string[][]>([["???", ""]]);
@@ -523,7 +526,7 @@ export function Root(props: IProps): React.ReactElement {
const textFile = new TextFile(scriptToSave.fileName, scriptToSave.code);
server.textFiles.push(textFile);
} else {
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or " + " or text file (.txt)");
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or a text file (.txt)");
return;
}
@@ -607,7 +610,7 @@ export function Root(props: IProps): React.ReactElement {
const textFile = new TextFile(currentScript.fileName, currentScript.code);
server.textFiles.push(textFile);
} else {
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or " + " or text file (.txt)");
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or a text file (.txt)");
return;
}
@@ -688,7 +691,7 @@ export function Root(props: IProps): React.ReactElement {
if (serverScriptIndex === -1 || savedScriptCode !== server.scripts[serverScriptIndex as number].code) {
PromptEvent.emit({
txt: `Do you want to save changes to ${closingScript.fileName} on ${closingScript.hostname}?`,
resolve: (result: boolean) => {
resolve: (result: boolean | string) => {
if (result) {
// Save changes
closingScript.code = savedScriptCode;
@@ -745,7 +748,7 @@ export function Root(props: IProps): React.ReactElement {
"Do you want to overwrite the current editor content with the contents of " +
openScript.fileName +
" on the server? This cannot be undone.",
resolve: (result: boolean) => {
resolve: (result: boolean | string) => {
if (result) {
// Save changes
openScript.code = serverScriptCode;
@@ -787,6 +790,16 @@ export function Root(props: IProps): React.ReactElement {
const serverScript = server.scripts.find((s) => s.filename === openScript.fileName);
return serverScript?.code ?? null;
}
function handleFilterChange(event: React.ChangeEvent<HTMLInputElement>): void {
setFilter(event.target.value);
}
function handleExpandSearch(): void {
setFilter("")
setSearchExpanded(!searchExpanded)
}
const filteredOpenScripts = Object.values(openScripts).filter(
(script) => (script.hostname.includes(filter) || script.fileName.includes(filter))
);
// Toolbars are roughly 112px:
// 8px body margin top
@@ -797,7 +810,7 @@ export function Root(props: IProps): React.ReactElement {
const editorHeight = dimensions.height - (130 + (options.vim ? 34 : 0));
const tabsMaxWidth = 1640;
const tabMargin = 5;
const tabMaxWidth = openScripts.length ? tabsMaxWidth / openScripts.length - tabMargin : 0;
const tabMaxWidth = filteredOpenScripts.length ? tabsMaxWidth / filteredOpenScripts.length - tabMargin : 0;
const tabIconWidth = 25;
const tabTextWidth = tabMaxWidth - tabIconWidth * 2;
return (
@@ -821,7 +834,20 @@ export function Root(props: IProps): React.ReactElement {
overflowX: "scroll",
}}
>
{openScripts.map(({ fileName, hostname }, index) => {
<Tooltip title={"Search Open Scripts"}>
{searchExpanded ?
<TextField
value={filter}
onChange={handleFilterChange}
autoFocus
InputProps={{
startAdornment: <SearchIcon />,
spellCheck: false,
endAdornment: <CloseIcon onClick={handleExpandSearch} />
}}
/> : <Button onClick={handleExpandSearch} ><SearchIcon /></Button>}
</Tooltip>
{filteredOpenScripts.map(({ fileName, hostname }, index) => {
const editingCurrentScript = currentScript?.fileName === openScripts[index].fileName &&
currentScript?.hostname === openScripts[index].hostname
const externalScript = hostname !== 'home'
@@ -838,7 +864,6 @@ export function Root(props: IProps): React.ReactElement {
if (externalScript) {
colorProps.color = Settings.theme.info
}
const iconButtonStyle = {
maxWidth: `${tabIconWidth}px`,
minWidth: `${tabIconWidth}px`,