mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-27 18:13:52 +01:00
fix mc
This commit is contained in:
commit
c5e29dafc4
32
dist/vendor.bundle.js
vendored
32
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
File diff suppressed because one or more lines are too long
@ -38,7 +38,13 @@ export function CityTabs(props: IProps): React.ReactElement {
|
||||
</Tabs>
|
||||
|
||||
{city !== "Expand" ? (
|
||||
<Industry rerender={props.rerender} city={city} warehouse={division.warehouses[city]} office={office} />
|
||||
<Industry
|
||||
key={city}
|
||||
rerender={props.rerender}
|
||||
city={city}
|
||||
warehouse={division.warehouses[city]}
|
||||
office={office}
|
||||
/>
|
||||
) : (
|
||||
<ExpandNewCity cityStateSetter={setCity} />
|
||||
)}
|
||||
|
@ -122,7 +122,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
</>
|
||||
);
|
||||
}
|
||||
console.log(division.products);
|
||||
|
||||
for (const prodName in division.products) {
|
||||
const prod = division.products[prodName];
|
||||
if (prod === undefined) continue;
|
||||
|
@ -25,7 +25,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
if (n === null) return <></>;
|
||||
const r = ResearchMap[n.text];
|
||||
let disabled = division.sciResearch.qty < r.cost;
|
||||
let disabled = division.sciResearch.qty < r.cost || n.researched;
|
||||
const parent = n.parent;
|
||||
if (parent !== null) {
|
||||
disabled = disabled || !parent.researched;
|
||||
|
@ -11,10 +11,11 @@ Source-File minus 1 is extremely weak because it can be fully level up quickly.
|
||||
*/
|
||||
|
||||
export enum Exploit {
|
||||
UndocumentedFunctionCall = "UndocumentedFunctionCall",
|
||||
Unclickable = "Unclickable",
|
||||
PrototypeTampering = "PrototypeTampering",
|
||||
Bypass = "Bypass",
|
||||
PrototypeTampering = "PrototypeTampering",
|
||||
Unclickable = "Unclickable",
|
||||
UndocumentedFunctionCall = "UndocumentedFunctionCall",
|
||||
TimeCompression = "TimeCompression",
|
||||
// To the players reading this. Yes you're supposed to add EditSaveFile by
|
||||
// editing your save file, yes you could add them all, no we don't care
|
||||
// that's not the point.
|
||||
@ -24,11 +25,12 @@ export enum Exploit {
|
||||
const names: {
|
||||
[key: string]: string;
|
||||
} = {
|
||||
UndocumentedFunctionCall: "by looking beyond the documentation.",
|
||||
Bypass: "by circumventing the ram cost of document.",
|
||||
EditSaveFile: "by editing your save file.",
|
||||
PrototypeTampering: "by tampering with Numbers prototype.",
|
||||
TimeCompression: "by compressing time",
|
||||
Unclickable: "by clicking the unclickable.",
|
||||
Bypass: "by circumventing the ram cost of document.",
|
||||
UndocumentedFunctionCall: "by looking beyond the documentation.",
|
||||
};
|
||||
|
||||
export function ExploitName(exploit: string): string {
|
||||
|
35
src/Exploits/loops.ts
Normal file
35
src/Exploits/loops.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Player } from "../Player";
|
||||
import { Exploit } from "./Exploit";
|
||||
|
||||
function tampering(): void {
|
||||
if (Player.exploits.includes(Exploit.PrototypeTampering)) return;
|
||||
// Tampering
|
||||
const a = 55;
|
||||
setInterval(function () {
|
||||
if (a.toExponential() !== "5.5e+1") {
|
||||
Player.giveExploit(Exploit.PrototypeTampering);
|
||||
}
|
||||
}, 15 * 60 * 1000); // 15 minutes
|
||||
}
|
||||
|
||||
function timeCompression(): void {
|
||||
if (Player.exploits.includes(Exploit.TimeCompression)) return;
|
||||
// Time compression
|
||||
let last = new Date().getTime();
|
||||
function minute(): void {
|
||||
const now = new Date().getTime();
|
||||
if (now - last < 500) {
|
||||
// time has been compressed.
|
||||
Player.giveExploit(Exploit.TimeCompression);
|
||||
return;
|
||||
}
|
||||
last = now;
|
||||
setTimeout(minute, 1000);
|
||||
}
|
||||
setTimeout(minute, 1000);
|
||||
}
|
||||
|
||||
export function startExploits(): void {
|
||||
tampering();
|
||||
timeCompression();
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { Player } from "../Player";
|
||||
import { Exploit } from "./Exploit";
|
||||
|
||||
export function startTampering(): void {
|
||||
const a = 55;
|
||||
setInterval(function () {
|
||||
if (a.toExponential() !== "5.5e+1") {
|
||||
Player.giveExploit(Exploit.PrototypeTampering);
|
||||
}
|
||||
}, 15 * 60 * 1000); // 15 minutes
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import { isString } from "./utils/helpers/isString";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { WorkerScript } from "./Netscript/WorkerScript";
|
||||
|
||||
export function netscriptDelay(time: number, workerScript: WorkerScript): Promise<void> {
|
||||
return new Promise(function (resolve) {
|
||||
workerScript.delay = setTimeoutRef(() => {
|
||||
workerScript.delay = window.setTimeout(() => {
|
||||
workerScript.delay = null;
|
||||
resolve();
|
||||
}, time);
|
||||
|
@ -54,13 +54,9 @@ import {
|
||||
calculateWeakenTime,
|
||||
} from "./Hacking";
|
||||
import { calculateServerGrowth } from "./Server/formulas/grow";
|
||||
import { Gang } from "./Gang/Gang";
|
||||
import { AllGangs } from "./Gang/AllGangs";
|
||||
import { GangMemberTasks } from "./Gang/GangMemberTasks";
|
||||
import { GangMemberUpgrades } from "./Gang/GangMemberUpgrades";
|
||||
import { Factions, factionExists } from "./Faction/Factions";
|
||||
import { joinFaction, purchaseAugmentation } from "./Faction/FactionHelpers";
|
||||
import { FactionWorkType } from "./Faction/FactionWorkTypeEnum";
|
||||
import { netscriptCanGrow, netscriptCanHack, netscriptCanWeaken } from "./Hacking/netscriptCanHack";
|
||||
|
||||
import {
|
||||
@ -136,13 +132,9 @@ import { workerScripts } from "./Netscript/WorkerScripts";
|
||||
import { WorkerScript } from "./Netscript/WorkerScript";
|
||||
import { makeRuntimeRejectMsg, netscriptDelay, resolveNetscriptRequestedThreads } from "./NetscriptEvaluator";
|
||||
import { Interpreter } from "./ThirdParty/JSInterpreter";
|
||||
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/SleeveHelpers";
|
||||
import { Exploit } from "./Exploits/Exploit";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { is2DArray } from "./utils/helpers/is2DArray";
|
||||
import { convertTimeMsToTimeElapsedString } from "./utils/StringHelperFunctions";
|
||||
|
||||
@ -162,13 +154,13 @@ import { Augmentation } from "./Augmentation/Augmentation";
|
||||
import { HacknetNode } from "./Hacknet/HacknetNode";
|
||||
|
||||
import { CodingContract } from "./CodingContracts";
|
||||
import { GangMember } from "./Gang/GangMember";
|
||||
import { GangMemberTask } from "./Gang/GangMemberTask";
|
||||
import { Stock } from "./StockMarket/Stock";
|
||||
import { BaseServer } from "./Server/BaseServer";
|
||||
|
||||
import { staneksGift } from "./CotMG/Helper";
|
||||
import { Fragments, FragmentById } from "./CotMG/Fragment";
|
||||
import { INetscriptGang, NetscriptGang } from "./NetscriptFunctions/Gang";
|
||||
import { INetscriptSleeve, NetscriptSleeve } from "./NetscriptFunctions/Sleeve";
|
||||
import { INetscriptExtra, NetscriptExtra } from "./NetscriptFunctions/Extra";
|
||||
import { INetscriptHacknet, NetscriptHacknet } from "./NetscriptFunctions/Hacknet";
|
||||
import { INetscriptStanek, NetscriptStanek } from "./NetscriptFunctions/Stanek";
|
||||
|
||||
const defaultInterpreter = new Interpreter("", () => undefined);
|
||||
|
||||
@ -205,8 +197,12 @@ function toNative(pseudoObj: any): any {
|
||||
return nativeObj;
|
||||
}
|
||||
|
||||
interface NS {
|
||||
interface NS extends INetscriptExtra {
|
||||
[key: string]: any;
|
||||
hacknet: INetscriptHacknet;
|
||||
gang: INetscriptGang;
|
||||
sleeve: INetscriptSleeve;
|
||||
stanek: INetscriptStanek;
|
||||
}
|
||||
|
||||
function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
@ -373,35 +369,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
};
|
||||
|
||||
// Utility function to get Hacknet Node object
|
||||
const getHacknetNode = function (i: any, callingFn = ""): HacknetNode | HacknetServer {
|
||||
if (isNaN(i)) {
|
||||
throw makeRuntimeErrorMsg(callingFn, "Invalid index specified for Hacknet Node: " + i);
|
||||
}
|
||||
if (i < 0 || i >= Player.hacknetNodes.length) {
|
||||
throw makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
}
|
||||
|
||||
if (hasHacknetServers(Player)) {
|
||||
const hi = Player.hacknetNodes[i];
|
||||
if (typeof hi !== "string") throw new Error("hacknet node was not a string");
|
||||
const hserver = AllServers[hi];
|
||||
if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server");
|
||||
if (hserver == null) {
|
||||
throw makeRuntimeErrorMsg(
|
||||
callingFn,
|
||||
`Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`,
|
||||
);
|
||||
}
|
||||
|
||||
return hserver;
|
||||
} else {
|
||||
const node = Player.hacknetNodes[i];
|
||||
if (!(node instanceof HacknetNode)) throw new Error("hacknet node was not node.");
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
const makeRuntimeErrorMsg = function (caller: string, msg: string): string {
|
||||
const errstack = new Error().stack;
|
||||
if (errstack === undefined) throw new Error("how did we not throw an error?");
|
||||
@ -517,23 +484,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
};
|
||||
|
||||
const checkSleeveAPIAccess = function (func: any): void {
|
||||
if (Player.bitNodeN !== 10 && !SourceFileFlags[10]) {
|
||||
throw makeRuntimeErrorMsg(
|
||||
`sleeve.${func}`,
|
||||
"You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const checkSleeveNumber = function (func: any, sleeveNumber: any): void {
|
||||
if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) {
|
||||
const msg = `Invalid sleeve number: ${sleeveNumber}`;
|
||||
workerScript.log(func, msg);
|
||||
throw makeRuntimeErrorMsg(`sleeve.${func}`, msg);
|
||||
}
|
||||
};
|
||||
|
||||
const getCodingContract = function (func: any, ip: any, fn: any): CodingContract {
|
||||
const server = safeGetServer(ip, func);
|
||||
const contract = server.getContract(fn);
|
||||
@ -553,31 +503,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
};
|
||||
|
||||
const checkGangApiAccess = function (func: any): void {
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Must have joined gang");
|
||||
const hasAccess = gang instanceof Gang;
|
||||
if (!hasAccess) {
|
||||
throw makeRuntimeErrorMsg(`gang.${func}`, `You do not currently have a Gang`);
|
||||
}
|
||||
};
|
||||
|
||||
const getGangMember = function (func: any, name: any): GangMember {
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Must have joined gang");
|
||||
for (const member of gang.members) if (member.name === name) return member;
|
||||
throw makeRuntimeErrorMsg(`gang.${func}`, `Invalid gang member: '${name}'`);
|
||||
};
|
||||
|
||||
const getGangTask = function (func: any, name: any): GangMemberTask {
|
||||
const task = GangMemberTasks[name];
|
||||
if (!task) {
|
||||
throw makeRuntimeErrorMsg(`gang.${func}`, `Invalid task: '${name}'`);
|
||||
}
|
||||
|
||||
return task;
|
||||
};
|
||||
|
||||
const getBladeburnerActionObject = function (func: any, type: any, name: any): any {
|
||||
const bladeburner = Player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
@ -796,142 +721,32 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return out;
|
||||
};
|
||||
|
||||
const functions = {
|
||||
hacknet: {
|
||||
numNodes: function (): any {
|
||||
return Player.hacknetNodes.length;
|
||||
},
|
||||
maxNumNodes: function (): any {
|
||||
if (hasHacknetServers(Player)) {
|
||||
return HacknetServerConstants.MaxServers;
|
||||
}
|
||||
return Infinity;
|
||||
},
|
||||
purchaseNode: function (): any {
|
||||
return purchaseHacknet(Player);
|
||||
},
|
||||
getPurchaseNodeCost: function (): any {
|
||||
if (hasHacknetServers(Player)) {
|
||||
return getCostOfNextHacknetServer(Player);
|
||||
} else {
|
||||
return getCostOfNextHacknetNode(Player);
|
||||
}
|
||||
},
|
||||
getNodeStats: function (i: any): any {
|
||||
const node = getHacknetNode(i, "getNodeStats");
|
||||
const hasUpgraded = hasHacknetServers(Player);
|
||||
const res: any = {
|
||||
name: node instanceof HacknetServer ? node.hostname : node.name,
|
||||
level: node.level,
|
||||
ram: node instanceof HacknetServer ? node.maxRam : node.ram,
|
||||
cores: node.cores,
|
||||
production: node instanceof HacknetServer ? node.hashRate : node.moneyGainRatePerSecond,
|
||||
timeOnline: node.onlineTimeSeconds,
|
||||
totalProduction: node instanceof HacknetServer ? node.totalHashesGenerated : node.totalMoneyGenerated,
|
||||
};
|
||||
|
||||
if (hasUpgraded && node instanceof HacknetServer) {
|
||||
res.cache = node.cache;
|
||||
res.hashCapacity = node.hashCapacity;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
upgradeLevel: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return purchaseLevelUpgrade(Player, node, n);
|
||||
},
|
||||
upgradeRam: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return purchaseRamUpgrade(Player, node, n);
|
||||
},
|
||||
upgradeCore: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return purchaseCoreUpgrade(Player, node, n);
|
||||
},
|
||||
upgradeCache: function (i: any, n: any): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("upgradeCache", "Can only be called on hacknet servers");
|
||||
return false;
|
||||
}
|
||||
const res = purchaseCacheUpgrade(Player, node, n);
|
||||
if (res) {
|
||||
updateHashManagerCapacity(Player);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getLevelUpgradeCost: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return node.calculateLevelUpgradeCost(n, Player.hacknet_node_level_cost_mult);
|
||||
},
|
||||
getRamUpgradeCost: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return node.calculateRamUpgradeCost(n, Player.hacknet_node_ram_cost_mult);
|
||||
},
|
||||
getCoreUpgradeCost: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return node.calculateCoreUpgradeCost(n, Player.hacknet_node_core_cost_mult);
|
||||
},
|
||||
getCacheUpgradeCost: function (i: any, n: any): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return Infinity;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("getCacheUpgradeCost", "Can only be called on hacknet servers");
|
||||
return -1;
|
||||
}
|
||||
return node.calculateCacheUpgradeCost(n);
|
||||
},
|
||||
numHashes: function (): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return 0;
|
||||
}
|
||||
return Player.hashManager.hashes;
|
||||
},
|
||||
hashCapacity: function (): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return 0;
|
||||
}
|
||||
return Player.hashManager.capacity;
|
||||
},
|
||||
hashCost: function (upgName: any): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return Player.hashManager.getUpgradeCost(upgName);
|
||||
},
|
||||
spendHashes: function (upgName: any, upgTarget: any): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
return purchaseHashUpgrade(Player, upgName, upgTarget);
|
||||
},
|
||||
getHashUpgradeLevel: function (upgName: any): any {
|
||||
const level = Player.hashManager.upgrades[upgName];
|
||||
if (level === undefined) {
|
||||
throw makeRuntimeErrorMsg("hacknet.hashUpgradeLevel", `Invalid Hash Upgrade: ${upgName}`);
|
||||
}
|
||||
return level;
|
||||
},
|
||||
getStudyMult: function (): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
return Player.hashManager.getStudyMult();
|
||||
},
|
||||
getTrainingMult: function (): any {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
return Player.hashManager.getTrainingMult();
|
||||
},
|
||||
const helper = {
|
||||
updateDynamicRam: updateDynamicRam,
|
||||
makeRuntimeErrorMsg: makeRuntimeErrorMsg,
|
||||
string: (funcName: string, argName: string, v: any): string => {
|
||||
if (typeof v === "string") return v;
|
||||
if (typeof v === "number") return v + ""; // cast to string;
|
||||
throw makeRuntimeErrorMsg(funcName, `${argName} should be a string`);
|
||||
},
|
||||
number: (funcName: string, argName: string, v: any): number => {
|
||||
if (typeof v === "number") return v;
|
||||
if (!isNaN(v) && !isNaN(parseFloat(v))) return parseFloat(v);
|
||||
throw makeRuntimeErrorMsg(funcName, `${argName} should be a number`);
|
||||
},
|
||||
boolean: (v: any): boolean => {
|
||||
return !!v; // Just convert it to boolean.
|
||||
},
|
||||
};
|
||||
|
||||
const gang = NetscriptGang(Player, workerScript, helper);
|
||||
const sleeve = NetscriptSleeve(Player, workerScript, helper);
|
||||
const extra = NetscriptExtra(Player, workerScript, helper);
|
||||
const hacknet = NetscriptHacknet(Player, workerScript, helper);
|
||||
const stanek = NetscriptStanek(Player, workerScript, helper);
|
||||
|
||||
const functions = {
|
||||
hacknet: hacknet,
|
||||
sprintf: sprintf,
|
||||
vsprintf: vsprintf,
|
||||
scan: function (ip: any = workerScript.serverIp, hostnames: any = true): any {
|
||||
@ -1057,7 +872,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return Promise.reject(workerScript);
|
||||
}
|
||||
const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable;
|
||||
server.moneyAvailable += 1 * threads; // It can be grown even if it has no money
|
||||
processSingleServerGrowth(server, threads, Player, host.cpuCores);
|
||||
const moneyAfter = server.moneyAvailable;
|
||||
workerScript.scriptRef.recordGrow(server.ip, threads);
|
||||
@ -1401,7 +1215,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
|
||||
const spawnDelay = 10;
|
||||
setTimeoutRef(() => {
|
||||
setTimeout(() => {
|
||||
if (isNaN(threads) || threads <= 0) {
|
||||
throw makeRuntimeErrorMsg("spawn", `Invalid thread count. Must be numeric and > 0, is ${threads}`);
|
||||
}
|
||||
@ -4084,7 +3898,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
checkSingularityAccess("softReset", 3);
|
||||
|
||||
workerScript.log("softReset", "Soft resetting. This will cause this script to be killed");
|
||||
setTimeoutRef(() => {
|
||||
setTimeout(() => {
|
||||
prestigeAugmentation();
|
||||
runAfterReset(cbScript);
|
||||
}, 0);
|
||||
@ -4103,7 +3917,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
|
||||
workerScript.log("installAugmentations", "Installing Augmentations. This will cause this script to be killed");
|
||||
setTimeoutRef(() => {
|
||||
setTimeout(() => {
|
||||
installAugmentations();
|
||||
runAfterReset(cbScript);
|
||||
}, 0);
|
||||
@ -4113,259 +3927,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
},
|
||||
|
||||
// Gang API
|
||||
gang: {
|
||||
createGang: function (faction: any): any {
|
||||
updateDynamicRam("createGang", getRamCost("gang", "createGang"));
|
||||
// this list is copied from Faction/ui/Root.tsx
|
||||
const GangNames = [
|
||||
"Slum Snakes",
|
||||
"Tetrads",
|
||||
"The Syndicate",
|
||||
"The Dark Army",
|
||||
"Speakers for the Dead",
|
||||
"NiteSec",
|
||||
"The Black Hand",
|
||||
];
|
||||
if (!Player.canAccessGang() || !GangNames.includes(faction)) return false;
|
||||
if (Player.inGang()) return false;
|
||||
if (!Player.factions.includes(faction)) return false;
|
||||
|
||||
const isHacking = faction === "NiteSec" || faction === "The Black Hand";
|
||||
Player.startGang(faction, isHacking);
|
||||
return true;
|
||||
},
|
||||
inGang: function (): any {
|
||||
updateDynamicRam("inGang", getRamCost("gang", "inGang"));
|
||||
return Player.inGang();
|
||||
},
|
||||
getMemberNames: function (): any {
|
||||
updateDynamicRam("getMemberNames", getRamCost("gang", "getMemberNames"));
|
||||
checkGangApiAccess("getMemberNames");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return gang.members.map((member) => member.name);
|
||||
},
|
||||
getGangInformation: function (): any {
|
||||
updateDynamicRam("getGangInformation", getRamCost("gang", "getGangInformation"));
|
||||
checkGangApiAccess("getGangInformation");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return {
|
||||
faction: gang.facName,
|
||||
isHacking: gang.isHackingGang,
|
||||
moneyGainRate: gang.moneyGainRate,
|
||||
power: gang.getPower(),
|
||||
respect: gang.respect,
|
||||
respectGainRate: gang.respectGainRate,
|
||||
territory: gang.getTerritory(),
|
||||
territoryClashChance: gang.territoryClashChance,
|
||||
territoryWarfareEngaged: gang.territoryWarfareEngaged,
|
||||
wantedLevel: gang.wanted,
|
||||
wantedLevelGainRate: gang.wantedGainRate,
|
||||
};
|
||||
},
|
||||
getOtherGangInformation: function (): any {
|
||||
updateDynamicRam("getOtherGangInformation", getRamCost("gang", "getOtherGangInformation"));
|
||||
checkGangApiAccess("getOtherGangInformation");
|
||||
const cpy: any = {};
|
||||
for (const gang in AllGangs) {
|
||||
cpy[gang] = Object.assign({}, AllGangs[gang]);
|
||||
}
|
||||
|
||||
return cpy;
|
||||
},
|
||||
getMemberInformation: function (name: any): any {
|
||||
updateDynamicRam("getMemberInformation", getRamCost("gang", "getMemberInformation"));
|
||||
checkGangApiAccess("getMemberInformation");
|
||||
const member = getGangMember("getMemberInformation", name);
|
||||
return {
|
||||
name: member.name,
|
||||
task: member.task,
|
||||
earnedRespect: member.earnedRespect,
|
||||
hack: member.hack,
|
||||
str: member.str,
|
||||
def: member.def,
|
||||
dex: member.dex,
|
||||
agi: member.agi,
|
||||
cha: member.cha,
|
||||
|
||||
hack_exp: member.hack_exp,
|
||||
str_exp: member.str_exp,
|
||||
def_exp: member.def_exp,
|
||||
dex_exp: member.dex_exp,
|
||||
agi_exp: member.agi_exp,
|
||||
cha_exp: member.cha_exp,
|
||||
|
||||
hack_mult: member.hack_mult,
|
||||
str_mult: member.str_mult,
|
||||
def_mult: member.def_mult,
|
||||
dex_mult: member.dex_mult,
|
||||
agi_mult: member.agi_mult,
|
||||
cha_mult: member.cha_mult,
|
||||
|
||||
hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points),
|
||||
str_asc_mult: member.calculateAscensionMult(member.str_asc_points),
|
||||
def_asc_mult: member.calculateAscensionMult(member.def_asc_points),
|
||||
dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points),
|
||||
agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points),
|
||||
cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points),
|
||||
|
||||
hack_asc_points: member.hack_asc_points,
|
||||
str_asc_points: member.str_asc_points,
|
||||
def_asc_points: member.def_asc_points,
|
||||
dex_asc_points: member.dex_asc_points,
|
||||
agi_asc_points: member.agi_asc_points,
|
||||
cha_asc_points: member.cha_asc_points,
|
||||
|
||||
upgrades: member.upgrades.slice(),
|
||||
augmentations: member.augmentations.slice(),
|
||||
};
|
||||
},
|
||||
canRecruitMember: function (): any {
|
||||
updateDynamicRam("canRecruitMember", getRamCost("gang", "canRecruitMember"));
|
||||
checkGangApiAccess("canRecruitMember");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return gang.canRecruitMember();
|
||||
},
|
||||
recruitMember: function (name: any): any {
|
||||
updateDynamicRam("recruitMember", getRamCost("gang", "recruitMember"));
|
||||
checkGangApiAccess("recruitMember");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const recruited = gang.recruitMember(name);
|
||||
if (recruited) {
|
||||
workerScript.log("recruitMember", `Successfully recruited Gang Member '${name}'`);
|
||||
} else {
|
||||
workerScript.log("recruitMember", `Failed to recruit Gang Member '${name}'`);
|
||||
}
|
||||
|
||||
return recruited;
|
||||
},
|
||||
getTaskNames: function (): any {
|
||||
updateDynamicRam("getTaskNames", getRamCost("gang", "getTaskNames"));
|
||||
checkGangApiAccess("getTaskNames");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const tasks = gang.getAllTaskNames();
|
||||
tasks.unshift("Unassigned");
|
||||
return tasks;
|
||||
},
|
||||
setMemberTask: function (memberName: any, taskName: any): any {
|
||||
updateDynamicRam("setMemberTask", getRamCost("gang", "setMemberTask"));
|
||||
checkGangApiAccess("setMemberTask");
|
||||
const member = getGangMember("setMemberTask", memberName);
|
||||
const success = member.assignToTask(taskName);
|
||||
if (success) {
|
||||
workerScript.log("setMemberTask", `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"setMemberTask",
|
||||
`Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`,
|
||||
);
|
||||
}
|
||||
|
||||
return success;
|
||||
},
|
||||
getTaskStats: function (taskName: any): any {
|
||||
updateDynamicRam("getTaskStats", getRamCost("gang", "getTaskStats"));
|
||||
checkGangApiAccess("getTaskStats");
|
||||
const task = getGangTask("getTaskStats", taskName);
|
||||
const copy = Object.assign({}, task);
|
||||
copy.territory = Object.assign({}, task.territory);
|
||||
return copy;
|
||||
},
|
||||
getEquipmentNames: function (): any {
|
||||
updateDynamicRam("getEquipmentNames", getRamCost("gang", "getEquipmentNames"));
|
||||
checkGangApiAccess("getEquipmentNames");
|
||||
return Object.keys(GangMemberUpgrades);
|
||||
},
|
||||
getEquipmentCost: function (equipName: any): any {
|
||||
updateDynamicRam("getEquipmentCost", getRamCost("gang", "getEquipmentCost"));
|
||||
checkGangApiAccess("getEquipmentCost");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg === null) return Infinity;
|
||||
return gang.getUpgradeCost(upg);
|
||||
},
|
||||
getEquipmentType: function (equipName: any): any {
|
||||
updateDynamicRam("getEquipmentType", getRamCost("gang", "getEquipmentType"));
|
||||
checkGangApiAccess("getEquipmentType");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg == null) return "";
|
||||
return upg.getType();
|
||||
},
|
||||
getEquipmentStats: function (equipName: any): any {
|
||||
updateDynamicRam("getEquipmentStats", getRamCost("gang", "getEquipmentStats"));
|
||||
checkGangApiAccess("getEquipmentStats");
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) {
|
||||
throw makeRuntimeErrorMsg("getEquipmentStats", `Invalid equipment: ${equipName}`);
|
||||
}
|
||||
return Object.assign({}, equipment.mults);
|
||||
},
|
||||
purchaseEquipment: function (memberName: any, equipName: any): any {
|
||||
updateDynamicRam("purchaseEquipment", getRamCost("gang", "purchaseEquipment"));
|
||||
checkGangApiAccess("purchaseEquipment");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("purchaseEquipment", memberName);
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) return false;
|
||||
const res = member.buyUpgrade(equipment, Player, gang);
|
||||
if (res) {
|
||||
workerScript.log("purchaseEquipment", `Purchased '${equipName}' for Gang member '${memberName}'`);
|
||||
} else {
|
||||
workerScript.log("purchaseEquipment", `Failed to purchase '${equipName}' for Gang member '${memberName}'`);
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
ascendMember: function (name: any): any {
|
||||
updateDynamicRam("ascendMember", getRamCost("gang", "ascendMember"));
|
||||
checkGangApiAccess("ascendMember");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("ascendMember", name);
|
||||
if (!member.canAscend()) return;
|
||||
return gang.ascendMember(member, workerScript);
|
||||
},
|
||||
setTerritoryWarfare: function (engage: any): any {
|
||||
updateDynamicRam("setTerritoryWarfare", getRamCost("gang", "setTerritoryWarfare"));
|
||||
checkGangApiAccess("setTerritoryWarfare");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (engage) {
|
||||
gang.territoryWarfareEngaged = true;
|
||||
workerScript.log("setTerritoryWarfare", "Engaging in Gang Territory Warfare");
|
||||
} else {
|
||||
gang.territoryWarfareEngaged = false;
|
||||
workerScript.log("setTerritoryWarfare", "Disengaging in Gang Territory Warfare");
|
||||
}
|
||||
},
|
||||
getChanceToWinClash: function (otherGang: any): any {
|
||||
updateDynamicRam("getChanceToWinClash", getRamCost("gang", "getChanceToWinClash"));
|
||||
checkGangApiAccess("getChanceToWinClash");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (AllGangs[otherGang] == null) {
|
||||
throw makeRuntimeErrorMsg(`gang.getChanceToWinClash`, `Invalid gang: ${otherGang}`);
|
||||
}
|
||||
|
||||
const playerPower = AllGangs[gang.facName].power;
|
||||
const otherPower = AllGangs[otherGang].power;
|
||||
|
||||
return playerPower / (otherPower + playerPower);
|
||||
},
|
||||
getBonusTime: function (): any {
|
||||
updateDynamicRam("getBonusTime", getRamCost("gang", "getBonusTime"));
|
||||
checkGangApiAccess("getBonusTime");
|
||||
const gang = Player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return Math.round(gang.storedCycles / 5);
|
||||
},
|
||||
}, // end gang namespace
|
||||
gang: gang,
|
||||
|
||||
// Bladeburner API
|
||||
bladeburner: {
|
||||
@ -4941,286 +4503,10 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}, // End coding contracts
|
||||
|
||||
// Duplicate Sleeve API
|
||||
sleeve: {
|
||||
getNumSleeves: function (): any {
|
||||
updateDynamicRam("getNumSleeves", getRamCost("sleeve", "getNumSleeves"));
|
||||
checkSleeveAPIAccess("getNumSleeves");
|
||||
return Player.sleeves.length;
|
||||
},
|
||||
setToShockRecovery: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("setToShockRecovery", getRamCost("sleeve", "setToShockRecovery"));
|
||||
checkSleeveAPIAccess("setToShockRecovery");
|
||||
checkSleeveNumber("setToShockRecovery", sleeveNumber);
|
||||
return Player.sleeves[sleeveNumber].shockRecovery(Player);
|
||||
},
|
||||
setToSynchronize: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("setToSynchronize", getRamCost("sleeve", "setToSynchronize"));
|
||||
checkSleeveAPIAccess("setToSynchronize");
|
||||
checkSleeveNumber("setToSynchronize", sleeveNumber);
|
||||
return Player.sleeves[sleeveNumber].synchronize(Player);
|
||||
},
|
||||
setToCommitCrime: function (sleeveNumber: any = 0, crimeName: any = ""): any {
|
||||
updateDynamicRam("setToCommitCrime", getRamCost("sleeve", "setToCommitCrime"));
|
||||
checkSleeveAPIAccess("setToCommitCrime");
|
||||
checkSleeveNumber("setToCommitCrime", sleeveNumber);
|
||||
return Player.sleeves[sleeveNumber].commitCrime(Player, crimeName);
|
||||
},
|
||||
setToUniversityCourse: function (sleeveNumber: any = 0, universityName: any = "", className: any = ""): any {
|
||||
updateDynamicRam("setToUniversityCourse", getRamCost("sleeve", "setToUniversityCourse"));
|
||||
checkSleeveAPIAccess("setToUniversityCourse");
|
||||
checkSleeveNumber("setToUniversityCourse", sleeveNumber);
|
||||
return Player.sleeves[sleeveNumber].takeUniversityCourse(Player, universityName, className);
|
||||
},
|
||||
travel: function (sleeveNumber: any = 0, cityName: any = ""): any {
|
||||
updateDynamicRam("travel", getRamCost("sleeve", "travel"));
|
||||
checkSleeveAPIAccess("travel");
|
||||
checkSleeveNumber("travel", sleeveNumber);
|
||||
return Player.sleeves[sleeveNumber].travel(Player, cityName);
|
||||
},
|
||||
setToCompanyWork: function (sleeveNumber: any = 0, companyName: any = ""): any {
|
||||
updateDynamicRam("setToCompanyWork", getRamCost("sleeve", "setToCompanyWork"));
|
||||
checkSleeveAPIAccess("setToCompanyWork");
|
||||
checkSleeveNumber("setToCompanyWork", sleeveNumber);
|
||||
sleeve: sleeve,
|
||||
|
||||
// Cannot work at the same company that another sleeve is working at
|
||||
for (let i = 0; i < Player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = Player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) {
|
||||
throw makeRuntimeErrorMsg(
|
||||
"sleeve.setToFactionWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
stanek: stanek,
|
||||
|
||||
return Player.sleeves[sleeveNumber].workForCompany(Player, companyName);
|
||||
},
|
||||
setToFactionWork: function (sleeveNumber: any = 0, factionName: any = "", workType: any = ""): any {
|
||||
updateDynamicRam("setToFactionWork", getRamCost("sleeve", "setToFactionWork"));
|
||||
checkSleeveAPIAccess("setToFactionWork");
|
||||
checkSleeveNumber("setToFactionWork", sleeveNumber);
|
||||
|
||||
// Cannot work at the same faction that another sleeve is working at
|
||||
for (let i = 0; i < Player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = Player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) {
|
||||
throw makeRuntimeErrorMsg(
|
||||
"sleeve.setToFactionWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Player.sleeves[sleeveNumber].workForFaction(Player, factionName, workType);
|
||||
},
|
||||
setToGymWorkout: function (sleeveNumber: any = 0, gymName: any = "", stat: any = ""): any {
|
||||
updateDynamicRam("setToGymWorkout", getRamCost("sleeve", "setToGymWorkout"));
|
||||
checkSleeveAPIAccess("setToGymWorkout");
|
||||
checkSleeveNumber("setToGymWorkout", sleeveNumber);
|
||||
|
||||
return Player.sleeves[sleeveNumber].workoutAtGym(Player, gymName, stat);
|
||||
},
|
||||
getSleeveStats: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("getSleeveStats", getRamCost("sleeve", "getSleeveStats"));
|
||||
checkSleeveAPIAccess("getSleeveStats");
|
||||
checkSleeveNumber("getSleeveStats", sleeveNumber);
|
||||
|
||||
const sl = Player.sleeves[sleeveNumber];
|
||||
return {
|
||||
shock: 100 - sl.shock,
|
||||
sync: sl.sync,
|
||||
hacking_skill: sl.hacking_skill,
|
||||
strength: sl.strength,
|
||||
defense: sl.defense,
|
||||
dexterity: sl.dexterity,
|
||||
agility: sl.agility,
|
||||
charisma: sl.charisma,
|
||||
};
|
||||
},
|
||||
getTask: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("getTask", getRamCost("sleeve", "getTask"));
|
||||
checkSleeveAPIAccess("getTask");
|
||||
checkSleeveNumber("getTask", sleeveNumber);
|
||||
|
||||
const sl = Player.sleeves[sleeveNumber];
|
||||
return {
|
||||
task: SleeveTaskType[sl.currentTask],
|
||||
crime: sl.crimeType,
|
||||
location: sl.currentTaskLocation,
|
||||
gymStatType: sl.gymStatType,
|
||||
factionWorkType: FactionWorkType[sl.factionWorkType],
|
||||
};
|
||||
},
|
||||
getInformation: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("getInformation", getRamCost("sleeve", "getInformation"));
|
||||
checkSleeveAPIAccess("getInformation");
|
||||
checkSleeveNumber("getInformation", sleeveNumber);
|
||||
|
||||
const sl = Player.sleeves[sleeveNumber];
|
||||
return {
|
||||
city: sl.city,
|
||||
hp: sl.hp,
|
||||
jobs: Object.keys(Player.jobs), // technically sleeves have the same jobs as the player.
|
||||
jobTitle: Object.values(Player.jobs),
|
||||
maxHp: sl.max_hp,
|
||||
tor: SpecialServerIps.hasOwnProperty("Darkweb Server"), // There's no reason not to give that infomation here as well. Worst case scenario it isn't used.
|
||||
|
||||
mult: {
|
||||
agility: sl.agility_mult,
|
||||
agilityExp: sl.agility_exp_mult,
|
||||
companyRep: sl.company_rep_mult,
|
||||
crimeMoney: sl.crime_money_mult,
|
||||
crimeSuccess: sl.crime_success_mult,
|
||||
defense: sl.defense_mult,
|
||||
defenseExp: sl.defense_exp_mult,
|
||||
dexterity: sl.dexterity_mult,
|
||||
dexterityExp: sl.dexterity_exp_mult,
|
||||
factionRep: sl.faction_rep_mult,
|
||||
hacking: sl.hacking_mult,
|
||||
hackingExp: sl.hacking_exp_mult,
|
||||
strength: sl.strength_mult,
|
||||
strengthExp: sl.strength_exp_mult,
|
||||
workMoney: sl.work_money_mult,
|
||||
},
|
||||
|
||||
timeWorked: sl.currentTaskTime,
|
||||
earningsForSleeves: {
|
||||
workHackExpGain: sl.earningsForSleeves.hack,
|
||||
workStrExpGain: sl.earningsForSleeves.str,
|
||||
workDefExpGain: sl.earningsForSleeves.def,
|
||||
workDexExpGain: sl.earningsForSleeves.dex,
|
||||
workAgiExpGain: sl.earningsForSleeves.agi,
|
||||
workChaExpGain: sl.earningsForSleeves.cha,
|
||||
workMoneyGain: sl.earningsForSleeves.money,
|
||||
},
|
||||
earningsForPlayer: {
|
||||
workHackExpGain: sl.earningsForPlayer.hack,
|
||||
workStrExpGain: sl.earningsForPlayer.str,
|
||||
workDefExpGain: sl.earningsForPlayer.def,
|
||||
workDexExpGain: sl.earningsForPlayer.dex,
|
||||
workAgiExpGain: sl.earningsForPlayer.agi,
|
||||
workChaExpGain: sl.earningsForPlayer.cha,
|
||||
workMoneyGain: sl.earningsForPlayer.money,
|
||||
},
|
||||
earningsForTask: {
|
||||
workHackExpGain: sl.earningsForTask.hack,
|
||||
workStrExpGain: sl.earningsForTask.str,
|
||||
workDefExpGain: sl.earningsForTask.def,
|
||||
workDexExpGain: sl.earningsForTask.dex,
|
||||
workAgiExpGain: sl.earningsForTask.agi,
|
||||
workChaExpGain: sl.earningsForTask.cha,
|
||||
workMoneyGain: sl.earningsForTask.money,
|
||||
},
|
||||
workRepGain: sl.getRepGain(Player),
|
||||
};
|
||||
},
|
||||
getSleeveAugmentations: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("getSleeveAugmentations", getRamCost("sleeve", "getSleeveAugmentations"));
|
||||
checkSleeveAPIAccess("getSleeveAugmentations");
|
||||
checkSleeveNumber("getSleeveAugmentations", sleeveNumber);
|
||||
|
||||
const augs = [];
|
||||
for (let i = 0; i < Player.sleeves[sleeveNumber].augmentations.length; i++) {
|
||||
augs.push(Player.sleeves[sleeveNumber].augmentations[i].name);
|
||||
}
|
||||
return augs;
|
||||
},
|
||||
getSleevePurchasableAugs: function (sleeveNumber: any = 0): any {
|
||||
updateDynamicRam("getSleevePurchasableAugs", getRamCost("sleeve", "getSleevePurchasableAugs"));
|
||||
checkSleeveAPIAccess("getSleevePurchasableAugs");
|
||||
checkSleeveNumber("getSleevePurchasableAugs", sleeveNumber);
|
||||
|
||||
const purchasableAugs = findSleevePurchasableAugs(Player.sleeves[sleeveNumber], Player);
|
||||
const augs = [];
|
||||
for (let i = 0; i < purchasableAugs.length; i++) {
|
||||
const aug = purchasableAugs[i];
|
||||
augs.push({
|
||||
name: aug.name,
|
||||
cost: aug.startingCost,
|
||||
});
|
||||
}
|
||||
|
||||
return augs;
|
||||
},
|
||||
purchaseSleeveAug: function (sleeveNumber: any = 0, augName: any = ""): any {
|
||||
updateDynamicRam("purchaseSleeveAug", getRamCost("sleeve", "purchaseSleeveAug"));
|
||||
checkSleeveAPIAccess("purchaseSleeveAug");
|
||||
checkSleeveNumber("purchaseSleeveAug", sleeveNumber);
|
||||
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug) {
|
||||
throw makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Invalid aug: ${augName}`);
|
||||
}
|
||||
|
||||
return Player.sleeves[sleeveNumber].tryBuyAugmentation(Player, aug);
|
||||
},
|
||||
}, // End sleeve
|
||||
|
||||
// Stanek's gift API
|
||||
stanek: {
|
||||
charge: function (worldX: any, worldY: any): any {
|
||||
updateDynamicRam("charge", getRamCost("stanek", "charge"));
|
||||
//checkStanekAPIAccess("charge");
|
||||
const fragment = staneksGift.fragmentAt(worldX, worldY);
|
||||
if (!fragment) throw makeRuntimeErrorMsg("stanek.charge", `No fragment at (${worldX}, ${worldY})`);
|
||||
return netscriptDelay(1000, workerScript).then(function () {
|
||||
if (workerScript.env.stopFlag) {
|
||||
return Promise.reject(workerScript);
|
||||
}
|
||||
const ram = workerScript.scriptRef.ramUsage * workerScript.scriptRef.threads;
|
||||
return Promise.resolve(staneksGift.charge(worldX, worldY, ram));
|
||||
});
|
||||
},
|
||||
fragmentDefinitions: function () {
|
||||
updateDynamicRam("fragmentDefinitions", getRamCost("stanek", "fragmentDefinitions"));
|
||||
//checkStanekAPIAccess("fragmentDefinitions");
|
||||
return Fragments.map((f) => f.copy());
|
||||
},
|
||||
placedFragments: function () {
|
||||
updateDynamicRam("placedFragments", getRamCost("stanek", "placedFragments"));
|
||||
//checkStanekAPIAccess("placedFragments");
|
||||
return staneksGift.fragments.map((af) => {
|
||||
return { ...af.copy(), ...af.fragment().copy() };
|
||||
});
|
||||
},
|
||||
clear: function () {
|
||||
updateDynamicRam("clear", getRamCost("stanek", "clear"));
|
||||
//checkStanekAPIAccess("clear");
|
||||
staneksGift.clear();
|
||||
},
|
||||
canPlace: function (worldX: any, worldY: any, fragmentId: any): any {
|
||||
updateDynamicRam("canPlace", getRamCost("stanek", "canPlace"));
|
||||
//checkStanekAPIAccess("canPlace");
|
||||
const fragment = FragmentById(fragmentId);
|
||||
if (!fragment) throw makeRuntimeErrorMsg("stanek.canPlace", `Invalid fragment id: ${fragmentId}`);
|
||||
return staneksGift.canPlace(worldX, worldY, fragment);
|
||||
},
|
||||
place: function (worldX: any, worldY: any, fragmentId: any): any {
|
||||
updateDynamicRam("place", getRamCost("stanek", "place"));
|
||||
//checkStanekAPIAccess("place");
|
||||
const fragment = FragmentById(fragmentId);
|
||||
if (!fragment) throw makeRuntimeErrorMsg("stanek.place", `Invalid fragment id: ${fragmentId}`);
|
||||
return staneksGift.place(worldX, worldY, fragment);
|
||||
},
|
||||
fragmentAt: function (worldX: any, worldY: any): any {
|
||||
updateDynamicRam("fragmentAt", getRamCost("stanek", "fragmentAt"));
|
||||
//checkStanekAPIAccess("fragmentAt");
|
||||
const fragment = staneksGift.fragmentAt(worldX, worldY);
|
||||
if (fragment !== null) return fragment.copy();
|
||||
return null;
|
||||
},
|
||||
deleteAt: function (worldX: any, worldY: any): any {
|
||||
updateDynamicRam("deleteAt", getRamCost("stanek", "deleteAt"));
|
||||
//checkStanekAPIAccess("deleteAt");
|
||||
return staneksGift.deleteAt(worldX, worldY);
|
||||
},
|
||||
}, // End stanek
|
||||
formulas: {
|
||||
basic: {
|
||||
calculateSkill: function (exp: any, mult: any = 1): any {
|
||||
@ -5328,28 +4614,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
},
|
||||
},
|
||||
}, // end formulas
|
||||
heart: {
|
||||
// Easter egg function
|
||||
break: function (): number {
|
||||
return Player.karma;
|
||||
},
|
||||
},
|
||||
exploit: function (): any {
|
||||
Player.giveExploit(Exploit.UndocumentedFunctionCall);
|
||||
},
|
||||
bypass: function (doc: any): any {
|
||||
// reset both fields first
|
||||
doc.completely_unused_field = undefined;
|
||||
const real_document: any = document;
|
||||
real_document.completely_unused_field = undefined;
|
||||
// set one to true and check that it affected the other.
|
||||
real_document.completely_unused_field = true;
|
||||
if (doc.completely_unused_field && workerScript.ramUsage === 1.6) {
|
||||
Player.giveExploit(Exploit.Bypass);
|
||||
}
|
||||
doc.completely_unused_field = undefined;
|
||||
real_document.completely_unused_field = undefined;
|
||||
},
|
||||
flags: function (data: any): any {
|
||||
data = toNative(data);
|
||||
// We always want the help flag.
|
||||
@ -5382,6 +4646,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
...extra,
|
||||
};
|
||||
|
||||
function getFunctionNames(obj: NS): string[] {
|
||||
|
39
src/NetscriptFunctions/Extra.ts
Normal file
39
src/NetscriptFunctions/Extra.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Exploit } from "../Exploits/Exploit";
|
||||
|
||||
export interface INetscriptExtra {
|
||||
heart: {
|
||||
break(): number;
|
||||
};
|
||||
exploit(): void;
|
||||
bypass(doc: Document): void;
|
||||
}
|
||||
|
||||
export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): INetscriptExtra {
|
||||
return {
|
||||
heart: {
|
||||
// Easter egg function
|
||||
break: function (): number {
|
||||
return player.karma;
|
||||
},
|
||||
},
|
||||
exploit: function (): void {
|
||||
player.giveExploit(Exploit.UndocumentedFunctionCall);
|
||||
},
|
||||
bypass: function (doc: any): void {
|
||||
// reset both fields first
|
||||
doc.completely_unused_field = undefined;
|
||||
const real_document: any = document;
|
||||
real_document.completely_unused_field = undefined;
|
||||
// set one to true and check that it affected the other.
|
||||
real_document.completely_unused_field = true;
|
||||
if (doc.completely_unused_field && workerScript.ramUsage === 1.6) {
|
||||
player.giveExploit(Exploit.Bypass);
|
||||
}
|
||||
doc.completely_unused_field = undefined;
|
||||
real_document.completely_unused_field = undefined;
|
||||
},
|
||||
};
|
||||
}
|
314
src/NetscriptFunctions/Gang.ts
Normal file
314
src/NetscriptFunctions/Gang.ts
Normal file
@ -0,0 +1,314 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { Gang } from "../Gang/Gang";
|
||||
import { AllGangs } from "../Gang/AllGangs";
|
||||
import { GangMemberTasks } from "../Gang/GangMemberTasks";
|
||||
import { GangMemberUpgrades } from "../Gang/GangMemberUpgrades";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { GangMember } from "../Gang/GangMember";
|
||||
import { GangMemberTask } from "../Gang/GangMemberTask";
|
||||
|
||||
export interface INetscriptGang {
|
||||
createGang(faction: string): boolean;
|
||||
inGang(): boolean;
|
||||
getMemberNames(): string[];
|
||||
getGangInformation(): any;
|
||||
getOtherGangInformation(): any;
|
||||
getMemberInformation(name: string): any;
|
||||
canRecruitMember(): boolean;
|
||||
recruitMember(name: string): boolean;
|
||||
getTaskNames(): string[];
|
||||
setMemberTask(memberName: string, taskName: string): boolean;
|
||||
getTaskStats(taskName: string): any;
|
||||
getEquipmentNames(): string[];
|
||||
getEquipmentCost(equipName: string): number;
|
||||
getEquipmentType(equipName: string): string;
|
||||
getEquipmentStats(equipName: string): any;
|
||||
purchaseEquipment(memberName: string, equipName: string): any;
|
||||
ascendMember(name: string): any;
|
||||
setTerritoryWarfare(engage: boolean): void;
|
||||
getChanceToWinClash(otherGang: string): number;
|
||||
getBonusTime(): number;
|
||||
}
|
||||
|
||||
export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): INetscriptGang {
|
||||
const checkGangApiAccess = function (func: string): void {
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Must have joined gang");
|
||||
const hasAccess = gang instanceof Gang;
|
||||
if (!hasAccess) {
|
||||
throw helper.makeRuntimeErrorMsg(`gang.${func}`, `You do not currently have a Gang`);
|
||||
}
|
||||
};
|
||||
|
||||
const getGangMember = function (func: string, name: string): GangMember {
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Must have joined gang");
|
||||
for (const member of gang.members) if (member.name === name) return member;
|
||||
throw helper.makeRuntimeErrorMsg(`gang.${func}`, `Invalid gang member: '${name}'`);
|
||||
};
|
||||
|
||||
const getGangTask = function (func: string, name: string): GangMemberTask {
|
||||
const task = GangMemberTasks[name];
|
||||
if (!task) {
|
||||
throw helper.makeRuntimeErrorMsg(`gang.${func}`, `Invalid task: '${name}'`);
|
||||
}
|
||||
|
||||
return task;
|
||||
};
|
||||
|
||||
return {
|
||||
createGang: function (faction: string): boolean {
|
||||
helper.updateDynamicRam("createGang", getRamCost("gang", "createGang"));
|
||||
// this list is copied from Faction/ui/Root.tsx
|
||||
const GangNames = [
|
||||
"Slum Snakes",
|
||||
"Tetrads",
|
||||
"The Syndicate",
|
||||
"The Dark Army",
|
||||
"Speakers for the Dead",
|
||||
"NiteSec",
|
||||
"The Black Hand",
|
||||
];
|
||||
if (!player.canAccessGang() || !GangNames.includes(faction)) return false;
|
||||
if (player.inGang()) return false;
|
||||
if (!player.factions.includes(faction)) return false;
|
||||
|
||||
const isHacking = faction === "NiteSec" || faction === "The Black Hand";
|
||||
player.startGang(faction, isHacking);
|
||||
return true;
|
||||
},
|
||||
inGang: function (): any {
|
||||
helper.updateDynamicRam("inGang", getRamCost("gang", "inGang"));
|
||||
return player.inGang();
|
||||
},
|
||||
getMemberNames: function (): any {
|
||||
helper.updateDynamicRam("getMemberNames", getRamCost("gang", "getMemberNames"));
|
||||
checkGangApiAccess("getMemberNames");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return gang.members.map((member) => member.name);
|
||||
},
|
||||
getGangInformation: function (): any {
|
||||
helper.updateDynamicRam("getGangInformation", getRamCost("gang", "getGangInformation"));
|
||||
checkGangApiAccess("getGangInformation");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return {
|
||||
faction: gang.facName,
|
||||
isHacking: gang.isHackingGang,
|
||||
moneyGainRate: gang.moneyGainRate,
|
||||
power: gang.getPower(),
|
||||
respect: gang.respect,
|
||||
respectGainRate: gang.respectGainRate,
|
||||
territory: gang.getTerritory(),
|
||||
territoryClashChance: gang.territoryClashChance,
|
||||
territoryWarfareEngaged: gang.territoryWarfareEngaged,
|
||||
wantedLevel: gang.wanted,
|
||||
wantedLevelGainRate: gang.wantedGainRate,
|
||||
};
|
||||
},
|
||||
getOtherGangInformation: function (): any {
|
||||
helper.updateDynamicRam("getOtherGangInformation", getRamCost("gang", "getOtherGangInformation"));
|
||||
checkGangApiAccess("getOtherGangInformation");
|
||||
const cpy: any = {};
|
||||
for (const gang in AllGangs) {
|
||||
cpy[gang] = Object.assign({}, AllGangs[gang]);
|
||||
}
|
||||
|
||||
return cpy;
|
||||
},
|
||||
getMemberInformation: function (name: any): any {
|
||||
helper.updateDynamicRam("getMemberInformation", getRamCost("gang", "getMemberInformation"));
|
||||
checkGangApiAccess("getMemberInformation");
|
||||
const member = getGangMember("getMemberInformation", name);
|
||||
return {
|
||||
name: member.name,
|
||||
task: member.task,
|
||||
earnedRespect: member.earnedRespect,
|
||||
hack: member.hack,
|
||||
str: member.str,
|
||||
def: member.def,
|
||||
dex: member.dex,
|
||||
agi: member.agi,
|
||||
cha: member.cha,
|
||||
|
||||
hack_exp: member.hack_exp,
|
||||
str_exp: member.str_exp,
|
||||
def_exp: member.def_exp,
|
||||
dex_exp: member.dex_exp,
|
||||
agi_exp: member.agi_exp,
|
||||
cha_exp: member.cha_exp,
|
||||
|
||||
hack_mult: member.hack_mult,
|
||||
str_mult: member.str_mult,
|
||||
def_mult: member.def_mult,
|
||||
dex_mult: member.dex_mult,
|
||||
agi_mult: member.agi_mult,
|
||||
cha_mult: member.cha_mult,
|
||||
|
||||
hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points),
|
||||
str_asc_mult: member.calculateAscensionMult(member.str_asc_points),
|
||||
def_asc_mult: member.calculateAscensionMult(member.def_asc_points),
|
||||
dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points),
|
||||
agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points),
|
||||
cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points),
|
||||
|
||||
hack_asc_points: member.hack_asc_points,
|
||||
str_asc_points: member.str_asc_points,
|
||||
def_asc_points: member.def_asc_points,
|
||||
dex_asc_points: member.dex_asc_points,
|
||||
agi_asc_points: member.agi_asc_points,
|
||||
cha_asc_points: member.cha_asc_points,
|
||||
|
||||
upgrades: member.upgrades.slice(),
|
||||
augmentations: member.augmentations.slice(),
|
||||
};
|
||||
},
|
||||
canRecruitMember: function (): any {
|
||||
helper.updateDynamicRam("canRecruitMember", getRamCost("gang", "canRecruitMember"));
|
||||
checkGangApiAccess("canRecruitMember");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return gang.canRecruitMember();
|
||||
},
|
||||
recruitMember: function (name: any): any {
|
||||
helper.updateDynamicRam("recruitMember", getRamCost("gang", "recruitMember"));
|
||||
checkGangApiAccess("recruitMember");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const recruited = gang.recruitMember(name);
|
||||
if (recruited) {
|
||||
workerScript.log("recruitMember", `Successfully recruited Gang Member '${name}'`);
|
||||
} else {
|
||||
workerScript.log("recruitMember", `Failed to recruit Gang Member '${name}'`);
|
||||
}
|
||||
|
||||
return recruited;
|
||||
},
|
||||
getTaskNames: function (): any {
|
||||
helper.updateDynamicRam("getTaskNames", getRamCost("gang", "getTaskNames"));
|
||||
checkGangApiAccess("getTaskNames");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const tasks = gang.getAllTaskNames();
|
||||
tasks.unshift("Unassigned");
|
||||
return tasks;
|
||||
},
|
||||
setMemberTask: function (memberName: any, taskName: any): any {
|
||||
helper.updateDynamicRam("setMemberTask", getRamCost("gang", "setMemberTask"));
|
||||
checkGangApiAccess("setMemberTask");
|
||||
const member = getGangMember("setMemberTask", memberName);
|
||||
const success = member.assignToTask(taskName);
|
||||
if (success) {
|
||||
workerScript.log("setMemberTask", `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"setMemberTask",
|
||||
`Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`,
|
||||
);
|
||||
}
|
||||
|
||||
return success;
|
||||
},
|
||||
getTaskStats: function (taskName: any): any {
|
||||
helper.updateDynamicRam("getTaskStats", getRamCost("gang", "getTaskStats"));
|
||||
checkGangApiAccess("getTaskStats");
|
||||
const task = getGangTask("getTaskStats", taskName);
|
||||
const copy = Object.assign({}, task);
|
||||
copy.territory = Object.assign({}, task.territory);
|
||||
return copy;
|
||||
},
|
||||
getEquipmentNames: function (): any {
|
||||
helper.updateDynamicRam("getEquipmentNames", getRamCost("gang", "getEquipmentNames"));
|
||||
checkGangApiAccess("getEquipmentNames");
|
||||
return Object.keys(GangMemberUpgrades);
|
||||
},
|
||||
getEquipmentCost: function (equipName: any): any {
|
||||
helper.updateDynamicRam("getEquipmentCost", getRamCost("gang", "getEquipmentCost"));
|
||||
checkGangApiAccess("getEquipmentCost");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg === null) return Infinity;
|
||||
return gang.getUpgradeCost(upg);
|
||||
},
|
||||
getEquipmentType: function (equipName: any): any {
|
||||
helper.updateDynamicRam("getEquipmentType", getRamCost("gang", "getEquipmentType"));
|
||||
checkGangApiAccess("getEquipmentType");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg == null) return "";
|
||||
return upg.getType();
|
||||
},
|
||||
getEquipmentStats: function (equipName: any): any {
|
||||
helper.updateDynamicRam("getEquipmentStats", getRamCost("gang", "getEquipmentStats"));
|
||||
checkGangApiAccess("getEquipmentStats");
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) {
|
||||
throw helper.makeRuntimeErrorMsg("getEquipmentStats", `Invalid equipment: ${equipName}`);
|
||||
}
|
||||
return Object.assign({}, equipment.mults);
|
||||
},
|
||||
purchaseEquipment: function (memberName: any, equipName: any): any {
|
||||
helper.updateDynamicRam("purchaseEquipment", getRamCost("gang", "purchaseEquipment"));
|
||||
checkGangApiAccess("purchaseEquipment");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("purchaseEquipment", memberName);
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) return false;
|
||||
const res = member.buyUpgrade(equipment, player, gang);
|
||||
if (res) {
|
||||
workerScript.log("purchaseEquipment", `Purchased '${equipName}' for Gang member '${memberName}'`);
|
||||
} else {
|
||||
workerScript.log("purchaseEquipment", `Failed to purchase '${equipName}' for Gang member '${memberName}'`);
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
ascendMember: function (name: any): any {
|
||||
helper.updateDynamicRam("ascendMember", getRamCost("gang", "ascendMember"));
|
||||
checkGangApiAccess("ascendMember");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("ascendMember", name);
|
||||
if (!member.canAscend()) return;
|
||||
return gang.ascendMember(member, workerScript);
|
||||
},
|
||||
setTerritoryWarfare: function (engage: any): void {
|
||||
helper.updateDynamicRam("setTerritoryWarfare", getRamCost("gang", "setTerritoryWarfare"));
|
||||
checkGangApiAccess("setTerritoryWarfare");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (engage) {
|
||||
gang.territoryWarfareEngaged = true;
|
||||
workerScript.log("setTerritoryWarfare", "Engaging in Gang Territory Warfare");
|
||||
} else {
|
||||
gang.territoryWarfareEngaged = false;
|
||||
workerScript.log("setTerritoryWarfare", "Disengaging in Gang Territory Warfare");
|
||||
}
|
||||
},
|
||||
getChanceToWinClash: function (otherGang: any): any {
|
||||
helper.updateDynamicRam("getChanceToWinClash", getRamCost("gang", "getChanceToWinClash"));
|
||||
checkGangApiAccess("getChanceToWinClash");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (AllGangs[otherGang] == null) {
|
||||
throw helper.makeRuntimeErrorMsg(`gang.getChanceToWinClash`, `Invalid gang: ${otherGang}`);
|
||||
}
|
||||
|
||||
const playerPower = AllGangs[gang.facName].power;
|
||||
const otherPower = AllGangs[otherGang].power;
|
||||
|
||||
return playerPower / (otherPower + playerPower);
|
||||
},
|
||||
getBonusTime: function (): any {
|
||||
helper.updateDynamicRam("getBonusTime", getRamCost("gang", "getBonusTime"));
|
||||
checkGangApiAccess("getBonusTime");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return Math.round(gang.storedCycles / 5);
|
||||
},
|
||||
};
|
||||
}
|
213
src/NetscriptFunctions/Hacknet.ts
Normal file
213
src/NetscriptFunctions/Hacknet.ts
Normal file
@ -0,0 +1,213 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { HacknetServerConstants } from "../Hacknet/data/Constants";
|
||||
import {
|
||||
getCostOfNextHacknetNode,
|
||||
getCostOfNextHacknetServer,
|
||||
hasHacknetServers,
|
||||
purchaseHacknet,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
purchaseCacheUpgrade,
|
||||
purchaseHashUpgrade,
|
||||
updateHashManagerCapacity,
|
||||
} from "../Hacknet/HacknetHelpers";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
import { HacknetNode } from "../Hacknet/HacknetNode";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
|
||||
export interface INetscriptHacknet {
|
||||
numNodes(): number;
|
||||
maxNumNodes(): number;
|
||||
purchaseNode(): any;
|
||||
getPurchaseNodeCost(): number;
|
||||
getNodeStats(i: number): any;
|
||||
upgradeLevel(i: number, n: number): boolean;
|
||||
upgradeRam(i: number, n: number): boolean;
|
||||
upgradeCore(i: number, n: number): boolean;
|
||||
upgradeCache(i: number, n: number): boolean;
|
||||
getLevelUpgradeCost(i: number, n: number): number;
|
||||
getRamUpgradeCost(i: number, n: number): number;
|
||||
getCoreUpgradeCost(i: number, n: number): number;
|
||||
getCacheUpgradeCost(i: number, n: number): number;
|
||||
numHashes(): number;
|
||||
hashCapacity(): number;
|
||||
hashCost(upgName: string): number;
|
||||
spendHashes(upgName: string, upgTarget: string): any;
|
||||
getHashUpgradeLevel(upgName: string): number;
|
||||
getStudyMult(): number;
|
||||
getTrainingMult(): number;
|
||||
}
|
||||
|
||||
export function NetscriptHacknet(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptHacknet {
|
||||
// Utility function to get Hacknet Node object
|
||||
const getHacknetNode = function (i: any, callingFn = ""): HacknetNode | HacknetServer {
|
||||
if (isNaN(i)) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, "Invalid index specified for Hacknet Node: " + i);
|
||||
}
|
||||
if (i < 0 || i >= player.hacknetNodes.length) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
}
|
||||
|
||||
if (hasHacknetServers(player)) {
|
||||
const hi = player.hacknetNodes[i];
|
||||
if (typeof hi !== "string") throw new Error("hacknet node was not a string");
|
||||
const hserver = AllServers[hi];
|
||||
if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server");
|
||||
if (hserver == null) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
callingFn,
|
||||
`Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`,
|
||||
);
|
||||
}
|
||||
|
||||
return hserver;
|
||||
} else {
|
||||
const node = player.hacknetNodes[i];
|
||||
if (!(node instanceof HacknetNode)) throw new Error("hacknet node was not node.");
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
numNodes: function (): any {
|
||||
return player.hacknetNodes.length;
|
||||
},
|
||||
maxNumNodes: function (): any {
|
||||
if (hasHacknetServers(player)) {
|
||||
return HacknetServerConstants.MaxServers;
|
||||
}
|
||||
return Infinity;
|
||||
},
|
||||
purchaseNode: function (): any {
|
||||
return purchaseHacknet(player);
|
||||
},
|
||||
getPurchaseNodeCost: function (): any {
|
||||
if (hasHacknetServers(player)) {
|
||||
return getCostOfNextHacknetServer(player);
|
||||
} else {
|
||||
return getCostOfNextHacknetNode(player);
|
||||
}
|
||||
},
|
||||
getNodeStats: function (i: any): any {
|
||||
const node = getHacknetNode(i, "getNodeStats");
|
||||
const hasUpgraded = hasHacknetServers(player);
|
||||
const res: any = {
|
||||
name: node instanceof HacknetServer ? node.hostname : node.name,
|
||||
level: node.level,
|
||||
ram: node instanceof HacknetServer ? node.maxRam : node.ram,
|
||||
cores: node.cores,
|
||||
production: node instanceof HacknetServer ? node.hashRate : node.moneyGainRatePerSecond,
|
||||
timeOnline: node.onlineTimeSeconds,
|
||||
totalProduction: node instanceof HacknetServer ? node.totalHashesGenerated : node.totalMoneyGenerated,
|
||||
};
|
||||
|
||||
if (hasUpgraded && node instanceof HacknetServer) {
|
||||
res.cache = node.cache;
|
||||
res.hashCapacity = node.hashCapacity;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
upgradeLevel: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return purchaseLevelUpgrade(player, node, n);
|
||||
},
|
||||
upgradeRam: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return purchaseRamUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCore: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return purchaseCoreUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCache: function (i: any, n: any): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("upgradeCache", "Can only be called on hacknet servers");
|
||||
return false;
|
||||
}
|
||||
const res = purchaseCacheUpgrade(player, node, n);
|
||||
if (res) {
|
||||
updateHashManagerCapacity(player);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getLevelUpgradeCost: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return node.calculateLevelUpgradeCost(n, player.hacknet_node_level_cost_mult);
|
||||
},
|
||||
getRamUpgradeCost: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return node.calculateRamUpgradeCost(n, player.hacknet_node_ram_cost_mult);
|
||||
},
|
||||
getCoreUpgradeCost: function (i: any, n: any): any {
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return node.calculateCoreUpgradeCost(n, player.hacknet_node_core_cost_mult);
|
||||
},
|
||||
getCacheUpgradeCost: function (i: any, n: any): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("getCacheUpgradeCost", "Can only be called on hacknet servers");
|
||||
return -1;
|
||||
}
|
||||
return node.calculateCacheUpgradeCost(n);
|
||||
},
|
||||
numHashes: function (): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return 0;
|
||||
}
|
||||
return player.hashManager.hashes;
|
||||
},
|
||||
hashCapacity: function (): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return 0;
|
||||
}
|
||||
return player.hashManager.capacity;
|
||||
},
|
||||
hashCost: function (upgName: any): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return player.hashManager.getUpgradeCost(upgName);
|
||||
},
|
||||
spendHashes: function (upgName: any, upgTarget: any): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
return purchaseHashUpgrade(player, upgName, upgTarget);
|
||||
},
|
||||
getHashUpgradeLevel: function (upgName: any): any {
|
||||
const level = player.hashManager.upgrades[upgName];
|
||||
if (level === undefined) {
|
||||
throw helper.makeRuntimeErrorMsg("hacknet.hashUpgradeLevel", `Invalid Hash Upgrade: ${upgName}`);
|
||||
}
|
||||
return level;
|
||||
},
|
||||
getStudyMult: function (): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
return player.hashManager.getStudyMult();
|
||||
},
|
||||
getTrainingMult: function (): any {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
return player.hashManager.getTrainingMult();
|
||||
},
|
||||
};
|
||||
}
|
7
src/NetscriptFunctions/INetscriptHelper.ts
Normal file
7
src/NetscriptFunctions/INetscriptHelper.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface INetscriptHelper {
|
||||
updateDynamicRam(functionName: string, ram: number): void;
|
||||
makeRuntimeErrorMsg(functionName: string, message: string): void;
|
||||
string(funcName: string, argName: string, v: any): string;
|
||||
number(funcName: string, argName: string, v: any): number;
|
||||
boolean(v: any): boolean;
|
||||
}
|
333
src/NetscriptFunctions/Sleeve.ts
Normal file
333
src/NetscriptFunctions/Sleeve.ts
Normal file
@ -0,0 +1,333 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { FactionWorkType } from "../Faction/FactionWorkTypeEnum";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
|
||||
export interface INetscriptSleeve {
|
||||
getNumSleeves(): number;
|
||||
setToShockRecovery(sleeveNumber?: number): boolean;
|
||||
setToSynchronize(sleeveNumber?: number): boolean;
|
||||
setToCommitCrime(sleeveNumber?: number, crimeName?: string): boolean;
|
||||
setToUniversityCourse(sleeveNumber?: number, universityName?: string, className?: string): boolean;
|
||||
travel(sleeveNumber?: number, cityName?: string): boolean;
|
||||
setToCompanyWork(sleeveNumber?: number, companyName?: string): boolean;
|
||||
setToFactionWork(sleeveNumber?: number, factionName?: string, workType?: string): boolean;
|
||||
setToGymWorkout(sleeveNumber?: number, gymName?: string, stat?: string): boolean;
|
||||
getSleeveStats(sleeveNumber?: number): {
|
||||
shock: number;
|
||||
sync: number;
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
};
|
||||
getTask(sleeveNumber?: number): {
|
||||
task: string;
|
||||
crime: string;
|
||||
location: string;
|
||||
gymStatType: string;
|
||||
factionWorkType: string;
|
||||
};
|
||||
getInformation(sleeveNumber?: number): any;
|
||||
getSleeveAugmentations(sleeveNumber?: number): string[];
|
||||
getSleevePurchasableAugs(sleeveNumber?: number): {
|
||||
name: string;
|
||||
cost: number;
|
||||
}[];
|
||||
purchaseSleeveAug(sleeveNumber?: number, augName?: string): boolean;
|
||||
}
|
||||
|
||||
export function NetscriptSleeve(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptSleeve {
|
||||
const checkSleeveAPIAccess = function (func: any): void {
|
||||
if (player.bitNodeN !== 10 && !SourceFileFlags[10]) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
`sleeve.${func}`,
|
||||
"You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const checkSleeveNumber = function (func: any, sleeveNumber: any): void {
|
||||
if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) {
|
||||
const msg = `Invalid sleeve number: ${sleeveNumber}`;
|
||||
workerScript.log(func, msg);
|
||||
throw helper.makeRuntimeErrorMsg(`sleeve.${func}`, msg);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getNumSleeves: function (): number {
|
||||
helper.updateDynamicRam("getNumSleeves", getRamCost("sleeve", "getNumSleeves"));
|
||||
checkSleeveAPIAccess("getNumSleeves");
|
||||
return player.sleeves.length;
|
||||
},
|
||||
setToShockRecovery: function (asleeveNumber: any = 0): boolean {
|
||||
const sleeveNumber = helper.number("setToShockRecovery", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("setToShockRecovery", getRamCost("sleeve", "setToShockRecovery"));
|
||||
checkSleeveAPIAccess("setToShockRecovery");
|
||||
checkSleeveNumber("setToShockRecovery", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].shockRecovery(player);
|
||||
},
|
||||
setToSynchronize: function (asleeveNumber: any = 0): boolean {
|
||||
const sleeveNumber = helper.number("setToSynchronize", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("setToSynchronize", getRamCost("sleeve", "setToSynchronize"));
|
||||
checkSleeveAPIAccess("setToSynchronize");
|
||||
checkSleeveNumber("setToSynchronize", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].synchronize(player);
|
||||
},
|
||||
setToCommitCrime: function (asleeveNumber: any = 0, acrimeName: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("setToCommitCrime", "sleeveNumber", asleeveNumber);
|
||||
const crimeName = helper.string("setToUniversityCourse", "crimeName", acrimeName);
|
||||
helper.updateDynamicRam("setToCommitCrime", getRamCost("sleeve", "setToCommitCrime"));
|
||||
checkSleeveAPIAccess("setToCommitCrime");
|
||||
checkSleeveNumber("setToCommitCrime", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].commitCrime(player, crimeName);
|
||||
},
|
||||
setToUniversityCourse: function (asleeveNumber: any = 0, auniversityName: any = "", aclassName: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("setToUniversityCourse", "sleeveNumber", asleeveNumber);
|
||||
const universityName = helper.string("setToUniversityCourse", "universityName", auniversityName);
|
||||
const className = helper.string("setToUniversityCourse", "className", aclassName);
|
||||
helper.updateDynamicRam("setToUniversityCourse", getRamCost("sleeve", "setToUniversityCourse"));
|
||||
checkSleeveAPIAccess("setToUniversityCourse");
|
||||
checkSleeveNumber("setToUniversityCourse", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
|
||||
},
|
||||
travel: function (asleeveNumber: any = 0, acityName: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("travel", "sleeveNumber", asleeveNumber);
|
||||
const cityName = helper.string("setToUniversityCourse", "cityName", acityName);
|
||||
helper.updateDynamicRam("travel", getRamCost("sleeve", "travel"));
|
||||
checkSleeveAPIAccess("travel");
|
||||
checkSleeveNumber("travel", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].travel(player, cityName as CityName);
|
||||
},
|
||||
setToCompanyWork: function (asleeveNumber: any = 0, acompanyName: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("setToCompanyWork", "sleeveNumber", asleeveNumber);
|
||||
const companyName = helper.string("setToUniversityCourse", "companyName", acompanyName);
|
||||
helper.updateDynamicRam("setToCompanyWork", getRamCost("sleeve", "setToCompanyWork"));
|
||||
checkSleeveAPIAccess("setToCompanyWork");
|
||||
checkSleeveNumber("setToCompanyWork", sleeveNumber);
|
||||
|
||||
// Cannot work at the same company that another sleeve is working at
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sleeve.setToFactionWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].workForCompany(player, companyName);
|
||||
},
|
||||
setToFactionWork: function (asleeveNumber: any = 0, afactionName: any = "", aworkType: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("setToFactionWork", "sleeveNumber", asleeveNumber);
|
||||
const factionName = helper.string("setToUniversityCourse", "factionName", afactionName);
|
||||
const workType = helper.string("setToUniversityCourse", "workType", aworkType);
|
||||
helper.updateDynamicRam("setToFactionWork", getRamCost("sleeve", "setToFactionWork"));
|
||||
checkSleeveAPIAccess("setToFactionWork");
|
||||
checkSleeveNumber("setToFactionWork", sleeveNumber);
|
||||
|
||||
// Cannot work at the same faction that another sleeve is working at
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sleeve.setToFactionWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].workForFaction(player, factionName, workType);
|
||||
},
|
||||
setToGymWorkout: function (asleeveNumber: any = 0, agymName: any = "", astat: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("setToGymWorkout", "sleeveNumber", asleeveNumber);
|
||||
const gymName = helper.string("setToUniversityCourse", "gymName", agymName);
|
||||
const stat = helper.string("setToUniversityCourse", "stat", astat);
|
||||
helper.updateDynamicRam("setToGymWorkout", getRamCost("sleeve", "setToGymWorkout"));
|
||||
checkSleeveAPIAccess("setToGymWorkout");
|
||||
checkSleeveNumber("setToGymWorkout", sleeveNumber);
|
||||
|
||||
return player.sleeves[sleeveNumber].workoutAtGym(player, gymName, stat);
|
||||
},
|
||||
getSleeveStats: function (asleeveNumber: any = 0): {
|
||||
shock: number;
|
||||
sync: number;
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
} {
|
||||
const sleeveNumber = helper.number("getSleeveStats", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("getSleeveStats", getRamCost("sleeve", "getSleeveStats"));
|
||||
checkSleeveAPIAccess("getSleeveStats");
|
||||
checkSleeveNumber("getSleeveStats", sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
shock: 100 - sl.shock,
|
||||
sync: sl.sync,
|
||||
hacking_skill: sl.hacking_skill,
|
||||
strength: sl.strength,
|
||||
defense: sl.defense,
|
||||
dexterity: sl.dexterity,
|
||||
agility: sl.agility,
|
||||
charisma: sl.charisma,
|
||||
};
|
||||
},
|
||||
getTask: function (asleeveNumber: any = 0): {
|
||||
task: string;
|
||||
crime: string;
|
||||
location: string;
|
||||
gymStatType: string;
|
||||
factionWorkType: string;
|
||||
} {
|
||||
const sleeveNumber = helper.number("getTask", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("getTask", getRamCost("sleeve", "getTask"));
|
||||
checkSleeveAPIAccess("getTask");
|
||||
checkSleeveNumber("getTask", sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
task: SleeveTaskType[sl.currentTask],
|
||||
crime: sl.crimeType,
|
||||
location: sl.currentTaskLocation,
|
||||
gymStatType: sl.gymStatType,
|
||||
factionWorkType: FactionWorkType[sl.factionWorkType],
|
||||
};
|
||||
},
|
||||
getInformation: function (asleeveNumber: any = 0): any {
|
||||
const sleeveNumber = helper.number("getInformation", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("getInformation", getRamCost("sleeve", "getInformation"));
|
||||
checkSleeveAPIAccess("getInformation");
|
||||
checkSleeveNumber("getInformation", sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
city: sl.city,
|
||||
hp: sl.hp,
|
||||
jobs: Object.keys(player.jobs), // technically sleeves have the same jobs as the player.
|
||||
jobTitle: Object.values(player.jobs),
|
||||
maxHp: sl.max_hp,
|
||||
tor: SpecialServerIps.hasOwnProperty("Darkweb Server"), // There's no reason not to give that infomation here as well. Worst case scenario it isn't used.
|
||||
|
||||
mult: {
|
||||
agility: sl.agility_mult,
|
||||
agilityExp: sl.agility_exp_mult,
|
||||
companyRep: sl.company_rep_mult,
|
||||
crimeMoney: sl.crime_money_mult,
|
||||
crimeSuccess: sl.crime_success_mult,
|
||||
defense: sl.defense_mult,
|
||||
defenseExp: sl.defense_exp_mult,
|
||||
dexterity: sl.dexterity_mult,
|
||||
dexterityExp: sl.dexterity_exp_mult,
|
||||
factionRep: sl.faction_rep_mult,
|
||||
hacking: sl.hacking_mult,
|
||||
hackingExp: sl.hacking_exp_mult,
|
||||
strength: sl.strength_mult,
|
||||
strengthExp: sl.strength_exp_mult,
|
||||
workMoney: sl.work_money_mult,
|
||||
},
|
||||
|
||||
timeWorked: sl.currentTaskTime,
|
||||
earningsForSleeves: {
|
||||
workHackExpGain: sl.earningsForSleeves.hack,
|
||||
workStrExpGain: sl.earningsForSleeves.str,
|
||||
workDefExpGain: sl.earningsForSleeves.def,
|
||||
workDexExpGain: sl.earningsForSleeves.dex,
|
||||
workAgiExpGain: sl.earningsForSleeves.agi,
|
||||
workChaExpGain: sl.earningsForSleeves.cha,
|
||||
workMoneyGain: sl.earningsForSleeves.money,
|
||||
},
|
||||
earningsForPlayer: {
|
||||
workHackExpGain: sl.earningsForPlayer.hack,
|
||||
workStrExpGain: sl.earningsForPlayer.str,
|
||||
workDefExpGain: sl.earningsForPlayer.def,
|
||||
workDexExpGain: sl.earningsForPlayer.dex,
|
||||
workAgiExpGain: sl.earningsForPlayer.agi,
|
||||
workChaExpGain: sl.earningsForPlayer.cha,
|
||||
workMoneyGain: sl.earningsForPlayer.money,
|
||||
},
|
||||
earningsForTask: {
|
||||
workHackExpGain: sl.earningsForTask.hack,
|
||||
workStrExpGain: sl.earningsForTask.str,
|
||||
workDefExpGain: sl.earningsForTask.def,
|
||||
workDexExpGain: sl.earningsForTask.dex,
|
||||
workAgiExpGain: sl.earningsForTask.agi,
|
||||
workChaExpGain: sl.earningsForTask.cha,
|
||||
workMoneyGain: sl.earningsForTask.money,
|
||||
},
|
||||
workRepGain: sl.getRepGain(player),
|
||||
};
|
||||
},
|
||||
getSleeveAugmentations: function (asleeveNumber: any = 0): string[] {
|
||||
const sleeveNumber = helper.number("getSleeveAugmentations", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("getSleeveAugmentations", getRamCost("sleeve", "getSleeveAugmentations"));
|
||||
checkSleeveAPIAccess("getSleeveAugmentations");
|
||||
checkSleeveNumber("getSleeveAugmentations", sleeveNumber);
|
||||
|
||||
const augs = [];
|
||||
for (let i = 0; i < player.sleeves[sleeveNumber].augmentations.length; i++) {
|
||||
augs.push(player.sleeves[sleeveNumber].augmentations[i].name);
|
||||
}
|
||||
return augs;
|
||||
},
|
||||
getSleevePurchasableAugs: function (asleeveNumber: any = 0): {
|
||||
name: string;
|
||||
cost: number;
|
||||
}[] {
|
||||
const sleeveNumber = helper.number("getSleevePurchasableAugs", "sleeveNumber", asleeveNumber);
|
||||
helper.updateDynamicRam("getSleevePurchasableAugs", getRamCost("sleeve", "getSleevePurchasableAugs"));
|
||||
checkSleeveAPIAccess("getSleevePurchasableAugs");
|
||||
checkSleeveNumber("getSleevePurchasableAugs", sleeveNumber);
|
||||
|
||||
const purchasableAugs = findSleevePurchasableAugs(player.sleeves[sleeveNumber], player);
|
||||
const augs = [];
|
||||
for (let i = 0; i < purchasableAugs.length; i++) {
|
||||
const aug = purchasableAugs[i];
|
||||
augs.push({
|
||||
name: aug.name,
|
||||
cost: aug.startingCost,
|
||||
});
|
||||
}
|
||||
|
||||
return augs;
|
||||
},
|
||||
purchaseSleeveAug: function (asleeveNumber: any = 0, aaugName: any = ""): boolean {
|
||||
const sleeveNumber = helper.number("purchaseSleeveAug", "sleeveNumber", asleeveNumber);
|
||||
const augName = helper.string("setToUniversityCourse", "augName", aaugName);
|
||||
helper.updateDynamicRam("purchaseSleeveAug", getRamCost("sleeve", "purchaseSleeveAug"));
|
||||
checkSleeveAPIAccess("purchaseSleeveAug");
|
||||
checkSleeveNumber("purchaseSleeveAug", sleeveNumber);
|
||||
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug) {
|
||||
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Invalid aug: ${augName}`);
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
|
||||
},
|
||||
};
|
||||
}
|
84
src/NetscriptFunctions/Stanek.ts
Normal file
84
src/NetscriptFunctions/Stanek.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { netscriptDelay } from "../NetscriptEvaluator";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
|
||||
import { staneksGift } from "../CotMG/Helper";
|
||||
import { Fragments, FragmentById } from "../CotMG/Fragment";
|
||||
|
||||
export interface INetscriptStanek {
|
||||
charge(worldX: any, worldY: any): any;
|
||||
fragmentDefinitions(): any;
|
||||
placedFragments(): any;
|
||||
clear(): any;
|
||||
canPlace(worldX: any, worldY: any, fragmentId: any): any;
|
||||
place(worldX: any, worldY: any, fragmentId: any): any;
|
||||
fragmentAt(worldX: any, worldY: any): any;
|
||||
deleteAt(worldX: any, worldY: any): any;
|
||||
}
|
||||
|
||||
export function NetscriptStanek(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptStanek {
|
||||
return {
|
||||
charge: function (worldX: any, worldY: any): any {
|
||||
helper.updateDynamicRam("charge", getRamCost("stanek", "charge"));
|
||||
//checkStanekAPIAccess("charge");
|
||||
const fragment = staneksGift.fragmentAt(worldX, worldY);
|
||||
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.charge", `No fragment at (${worldX}, ${worldY})`);
|
||||
return netscriptDelay(1000, workerScript).then(function () {
|
||||
if (workerScript.env.stopFlag) {
|
||||
return Promise.reject(workerScript);
|
||||
}
|
||||
const ram = workerScript.scriptRef.ramUsage * workerScript.scriptRef.threads;
|
||||
return Promise.resolve(staneksGift.charge(worldX, worldY, ram));
|
||||
});
|
||||
},
|
||||
fragmentDefinitions: function () {
|
||||
helper.updateDynamicRam("fragmentDefinitions", getRamCost("stanek", "fragmentDefinitions"));
|
||||
//checkStanekAPIAccess("fragmentDefinitions");
|
||||
return Fragments.map((f) => f.copy());
|
||||
},
|
||||
placedFragments: function () {
|
||||
helper.updateDynamicRam("placedFragments", getRamCost("stanek", "placedFragments"));
|
||||
//checkStanekAPIAccess("placedFragments");
|
||||
return staneksGift.fragments.map((af) => {
|
||||
return { ...af.copy(), ...af.fragment().copy() };
|
||||
});
|
||||
},
|
||||
clear: function () {
|
||||
helper.updateDynamicRam("clear", getRamCost("stanek", "clear"));
|
||||
//checkStanekAPIAccess("clear");
|
||||
staneksGift.clear();
|
||||
},
|
||||
canPlace: function (worldX: any, worldY: any, fragmentId: any): any {
|
||||
helper.updateDynamicRam("canPlace", getRamCost("stanek", "canPlace"));
|
||||
//checkStanekAPIAccess("canPlace");
|
||||
const fragment = FragmentById(fragmentId);
|
||||
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.canPlace", `Invalid fragment id: ${fragmentId}`);
|
||||
return staneksGift.canPlace(worldX, worldY, fragment);
|
||||
},
|
||||
place: function (worldX: any, worldY: any, fragmentId: any): any {
|
||||
helper.updateDynamicRam("place", getRamCost("stanek", "place"));
|
||||
//checkStanekAPIAccess("place");
|
||||
const fragment = FragmentById(fragmentId);
|
||||
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.place", `Invalid fragment id: ${fragmentId}`);
|
||||
return staneksGift.place(worldX, worldY, fragment);
|
||||
},
|
||||
fragmentAt: function (worldX: any, worldY: any): any {
|
||||
helper.updateDynamicRam("fragmentAt", getRamCost("stanek", "fragmentAt"));
|
||||
//checkStanekAPIAccess("fragmentAt");
|
||||
const fragment = staneksGift.fragmentAt(worldX, worldY);
|
||||
if (fragment !== null) return fragment.copy();
|
||||
return null;
|
||||
},
|
||||
deleteAt: function (worldX: any, worldY: any): any {
|
||||
helper.updateDynamicRam("deleteAt", getRamCost("stanek", "deleteAt"));
|
||||
//checkStanekAPIAccess("deleteAt");
|
||||
return staneksGift.deleteAt(worldX, worldY);
|
||||
},
|
||||
};
|
||||
}
|
@ -21,7 +21,6 @@ import { Script } from "./Script/Script";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { BaseServer } from "./Server/BaseServer";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import { generate } from "escodegen";
|
||||
|
||||
@ -265,7 +264,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript
|
||||
}
|
||||
|
||||
if (interpreter.step()) {
|
||||
setTimeoutRef(runInterpreter, Settings.CodeInstructionRunTime);
|
||||
setTimeout(runInterpreter, Settings.CodeInstructionRunTime);
|
||||
} else {
|
||||
resolve(workerScript);
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import { staneksGift, loadStaneksGift } from "./CotMG/Helper";
|
||||
|
||||
import { GameSavedEvents } from "./ui/React/Snackbar";
|
||||
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import * as ExportBonus from "./ExportBonus";
|
||||
|
||||
import { dialogBoxCreate } from "./ui/React/DialogBox";
|
||||
@ -105,7 +104,7 @@ class BitburnerSaveObject {
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(function () {
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
|
@ -7,7 +7,6 @@
|
||||
import { calculateRamUsage } from "./RamCalculations";
|
||||
import { ScriptUrl } from "./ScriptUrl";
|
||||
|
||||
import { setTimeoutRef } from "../utils/SetTimeoutRef";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||
|
||||
@ -70,7 +69,7 @@ export class Script {
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(function () {
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
|
@ -1,4 +1,5 @@
|
||||
export interface Options {
|
||||
theme: string;
|
||||
insertSpaces: boolean;
|
||||
fontSize: number;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import Typography from "@mui/material/Typography";
|
||||
import Select from "@mui/material/Select";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import TextField from "@mui/material/TextField";
|
||||
|
||||
interface IProps {
|
||||
options: Options;
|
||||
@ -19,15 +20,23 @@ interface IProps {
|
||||
export function OptionsModal(props: IProps): React.ReactElement {
|
||||
const [theme, setTheme] = useState(props.options.theme);
|
||||
const [insertSpaces, setInsertSpaces] = useState(props.options.insertSpaces);
|
||||
const [fontSize, setFontSize] = useState(props.options.fontSize);
|
||||
|
||||
function save(): void {
|
||||
props.save({
|
||||
theme: theme,
|
||||
insertSpaces: insertSpaces,
|
||||
fontSize: fontSize,
|
||||
});
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onFontChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const f = parseFloat(event.target.value);
|
||||
if (isNaN(f)) return;
|
||||
setFontSize(f);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
@ -42,6 +51,9 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
<Typography>Use whitespace over tabs: </Typography>
|
||||
<Switch onChange={(event) => setInsertSpaces(event.target.checked)} checked={insertSpaces} />
|
||||
</Box>
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
<TextField type="number" label="Font size" value={fontSize} onChange={onFontChange} />
|
||||
</Box>
|
||||
<br />
|
||||
<Button onClick={save}>Save</Button>
|
||||
</Modal>
|
||||
|
@ -31,7 +31,7 @@ import IconButton from "@mui/material/IconButton";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
|
||||
let symbols: string[] = [];
|
||||
(function () {
|
||||
export function SetupTextEditor(): void {
|
||||
const ns = NetscriptFunctions({} as WorkerScript);
|
||||
|
||||
function populate(ns: any): string[] {
|
||||
@ -52,7 +52,7 @@ let symbols: string[] = [];
|
||||
|
||||
const exclude = ["heart", "break", "exploit", "bypass", "corporation"];
|
||||
symbols = symbols.filter((symbol: string) => !exclude.includes(symbol));
|
||||
})();
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
filename: string;
|
||||
@ -87,6 +87,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
const [options, setOptions] = useState<Options>({
|
||||
theme: Settings.MonacoTheme,
|
||||
insertSpaces: Settings.MonacoInsertSpaces,
|
||||
fontSize: Settings.MonacoFontSize,
|
||||
});
|
||||
|
||||
// store the last known state in case we need to restart without nano.
|
||||
@ -329,11 +330,13 @@ export function Root(props: IProps): React.ReactElement {
|
||||
options={{
|
||||
theme: Settings.MonacoTheme,
|
||||
insertSpaces: Settings.MonacoInsertSpaces,
|
||||
fontSize: Settings.MonacoFontSize,
|
||||
}}
|
||||
save={(options: Options) => {
|
||||
setOptions(options);
|
||||
Settings.MonacoTheme = options.theme;
|
||||
Settings.MonacoInsertSpaces = options.insertSpaces;
|
||||
Settings.MonacoFontSize = options.fontSize;
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
@ -74,6 +74,7 @@ export function processSingleServerGrowth(server: Server, threads: number, p: IP
|
||||
}
|
||||
|
||||
const oldMoneyAvailable = server.moneyAvailable;
|
||||
server.moneyAvailable += 1 * threads; // It can be grown even if it has no money
|
||||
server.moneyAvailable *= serverGrowth;
|
||||
|
||||
// in case of data corruption
|
||||
|
@ -150,6 +150,8 @@ interface ISettings extends IDefaultSettings {
|
||||
MonacoTheme: string;
|
||||
|
||||
MonacoInsertSpaces: boolean;
|
||||
|
||||
MonacoFontSize: number;
|
||||
}
|
||||
|
||||
export const defaultSettings: IDefaultSettings = {
|
||||
@ -232,6 +234,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
SuppressBladeburnerPopup: defaultSettings.SuppressBladeburnerPopup,
|
||||
MonacoTheme: "vs-dark",
|
||||
MonacoInsertSpaces: false,
|
||||
MonacoFontSize: 10,
|
||||
|
||||
theme: {
|
||||
primarylight: defaultSettings.theme.primarylight,
|
||||
|
@ -13,10 +13,11 @@ export const TerminalHelpText: string[] = [
|
||||
"check [script] [args...] Print a script's logs to Terminal",
|
||||
"clear Clear all text on the terminal ",
|
||||
"cls See 'clear' command ",
|
||||
"connect [ip/hostname] Connects to a remote server",
|
||||
"connect [hostname] Connects to a remote server",
|
||||
"download [script/text file] Downloads scripts or text files to your computer",
|
||||
"expr [math expression] Evaluate a mathematical expression",
|
||||
"free Check the machine's memory (RAM) usage",
|
||||
"grow Spoof money in a servers bank account, increasing the amount available.",
|
||||
"hack Hack the current machine",
|
||||
"help [command] Display this help text, or the help text for a command",
|
||||
"home Connect to home computer",
|
||||
@ -39,6 +40,7 @@ export const TerminalHelpText: string[] = [
|
||||
"tail [script] [args...] Displays dynamic logs for the specified script",
|
||||
"top Displays all running scripts and their RAM usage",
|
||||
"unalias [alias name] Deletes the specified alias",
|
||||
"weaken [server] Reduce the security of a server",
|
||||
"wget [url] [target file] Retrieves code/text from a web server",
|
||||
];
|
||||
|
||||
@ -151,7 +153,7 @@ export const HelpTexts: IMap<string[]> = {
|
||||
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'clear' command",
|
||||
],
|
||||
connect: [
|
||||
"connect [hostname/ip]",
|
||||
"connect [hostname]",
|
||||
" ",
|
||||
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument ",
|
||||
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To ",
|
||||
@ -190,6 +192,12 @@ export const HelpTexts: IMap<string[]> = {
|
||||
"Display's the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as ",
|
||||
"how much of it is being used.",
|
||||
],
|
||||
grow: [
|
||||
"grow",
|
||||
"",
|
||||
"Spoof transactions in the current server. Increasing the money available by hacking. Requires root access.",
|
||||
"See the wiki page for hacking mechanics.",
|
||||
],
|
||||
hack: [
|
||||
"hack",
|
||||
" ",
|
||||
@ -394,6 +402,12 @@ export const HelpTexts: IMap<string[]> = {
|
||||
" ",
|
||||
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
||||
],
|
||||
weaken: [
|
||||
"weaken",
|
||||
"",
|
||||
"Reduces the security level of the current server. Decreasing the time it takes for all operations on this server.",
|
||||
"Requires root access. See the wiki page for hacking mechanics.",
|
||||
],
|
||||
wget: [
|
||||
"wget [url] [target file]",
|
||||
" ",
|
||||
|
@ -31,9 +31,9 @@ export class Link {
|
||||
export class TTimer {
|
||||
time: number;
|
||||
timeLeft: number;
|
||||
action: "h" | "b" | "a";
|
||||
action: "h" | "b" | "a" | "g" | "w";
|
||||
|
||||
constructor(time: number, action: "h" | "b" | "a") {
|
||||
constructor(time: number, action: "h" | "b" | "a" | "g" | "w") {
|
||||
this.time = time;
|
||||
this.timeLeft = time;
|
||||
this.action = action;
|
||||
@ -62,7 +62,11 @@ export interface ITerminal {
|
||||
startAnalyze(): void;
|
||||
startBackdoor(player: IPlayer): void;
|
||||
startHack(player: IPlayer): void;
|
||||
startGrow(player: IPlayer): void;
|
||||
startWeaken(player: IPlayer): void;
|
||||
finishHack(router: IRouter, player: IPlayer, cancelled?: boolean): void;
|
||||
finishGrow(player: IPlayer, cancelled?: boolean): void;
|
||||
finishWeaken(player: IPlayer, cancelled?: boolean): void;
|
||||
finishBackdoor(router: IRouter, player: IPlayer, cancelled?: boolean): void;
|
||||
finishAnalyze(player: IPlayer, cancelled?: boolean): void;
|
||||
finishAction(router: IRouter, player: IPlayer, cancelled?: boolean): void;
|
||||
|
@ -17,7 +17,7 @@ import { AllServers } from "../Server/AllServers";
|
||||
import { removeLeadingSlash, isInRootDirectory, evaluateFilePath } from "./DirectoryHelpers";
|
||||
import { checkIfConnectedToDarkweb } from "../DarkWeb/DarkWeb";
|
||||
import { iTutorialNextStep, iTutorialSteps, ITutorial } from "../InteractiveTutorial";
|
||||
import { GetServerByHostname, getServer, getServerOnNetwork } from "../Server/ServerHelpers";
|
||||
import { GetServerByHostname, getServer, getServerOnNetwork, processSingleServerGrowth } from "../Server/ServerHelpers";
|
||||
import { ParseCommand, ParseCommands } from "./Parser";
|
||||
import { SpecialServerIps, SpecialServerNames } from "../Server/SpecialServerIps";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
@ -27,6 +27,8 @@ import {
|
||||
calculateHackingExpGain,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingTime,
|
||||
calculateGrowTime,
|
||||
calculateWeakenTime,
|
||||
} from "../Hacking";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
@ -42,6 +44,7 @@ import { connect } from "./commands/connect";
|
||||
import { download } from "./commands/download";
|
||||
import { expr } from "./commands/expr";
|
||||
import { free } from "./commands/free";
|
||||
import { grow } from "./commands/grow";
|
||||
import { hack } from "./commands/hack";
|
||||
import { help } from "./commands/help";
|
||||
import { home } from "./commands/home";
|
||||
@ -64,6 +67,7 @@ import { sudov } from "./commands/sudov";
|
||||
import { tail } from "./commands/tail";
|
||||
import { top } from "./commands/top";
|
||||
import { unalias } from "./commands/unalias";
|
||||
import { weaken } from "./commands/weaken";
|
||||
import { wget } from "./commands/wget";
|
||||
|
||||
export class Terminal implements ITerminal {
|
||||
@ -115,6 +119,23 @@ export class Terminal implements ITerminal {
|
||||
this.startAction(calculateHackingTime(server, player) / 4, "h");
|
||||
}
|
||||
|
||||
startGrow(player: IPlayer): void {
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
this.startAction(calculateGrowTime(server, player) / 16, "g");
|
||||
}
|
||||
startWeaken(player: IPlayer): void {
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
this.startAction(calculateWeakenTime(server, player) / 16, "w");
|
||||
}
|
||||
|
||||
startBackdoor(player: IPlayer): void {
|
||||
// Backdoor should take the same amount of time as hack
|
||||
const server = player.getCurrentServer();
|
||||
@ -130,7 +151,7 @@ export class Terminal implements ITerminal {
|
||||
this.startAction(1, "a");
|
||||
}
|
||||
|
||||
startAction(n: number, action: "h" | "b" | "a"): void {
|
||||
startAction(n: number, action: "h" | "b" | "a" | "g" | "w"): void {
|
||||
this.action = new TTimer(n, action);
|
||||
}
|
||||
|
||||
@ -183,7 +204,6 @@ export class Terminal implements ITerminal {
|
||||
);
|
||||
} else {
|
||||
// Failure
|
||||
// player only gains 25% exp for failure? TODO Can change this later to balance
|
||||
player.gainHackingExp(expGainedOnFailure);
|
||||
this.print(
|
||||
`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`,
|
||||
@ -191,6 +211,39 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
}
|
||||
|
||||
finishGrow(player: IPlayer, cancelled = false): void {
|
||||
if (cancelled) return;
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
const expGain = calculateHackingExpGain(server, player);
|
||||
const growth = processSingleServerGrowth(server, 1, player, server.cpuCores) - 1;
|
||||
this.print(
|
||||
`Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage(
|
||||
growth,
|
||||
6,
|
||||
)}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp.`,
|
||||
);
|
||||
}
|
||||
|
||||
finishWeaken(player: IPlayer, cancelled = false): void {
|
||||
if (cancelled) return;
|
||||
const server = player.getCurrentServer();
|
||||
if (server instanceof HacknetServer) {
|
||||
this.error("Cannot hack this kind of server");
|
||||
return;
|
||||
}
|
||||
const expGain = calculateHackingExpGain(server, player);
|
||||
server.weaken(CONSTANTS.ServerWeakenAmount);
|
||||
this.print(
|
||||
`'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp(
|
||||
expGain,
|
||||
)} hacking exp.`,
|
||||
);
|
||||
}
|
||||
|
||||
finishBackdoor(router: IRouter, player: IPlayer, cancelled = false): void {
|
||||
if (!cancelled) {
|
||||
const server = player.getCurrentServer();
|
||||
@ -257,6 +310,10 @@ export class Terminal implements ITerminal {
|
||||
this.print(this.getProgressText());
|
||||
if (this.action.action === "h") {
|
||||
this.finishHack(router, player, cancelled);
|
||||
} else if (this.action.action === "g") {
|
||||
this.finishGrow(player, cancelled);
|
||||
} else if (this.action.action === "w") {
|
||||
this.finishWeaken(player, cancelled);
|
||||
} else if (this.action.action === "b") {
|
||||
this.finishBackdoor(router, player, cancelled);
|
||||
} else if (this.action.action === "a") {
|
||||
@ -657,6 +714,7 @@ export class Terminal implements ITerminal {
|
||||
args: (string | number)[],
|
||||
) => void;
|
||||
} = {
|
||||
"scan-analyze": scananalyze,
|
||||
alias: alias,
|
||||
analyze: analyze,
|
||||
backdoor: backdoor,
|
||||
@ -664,12 +722,13 @@ export class Terminal implements ITerminal {
|
||||
cat: cat,
|
||||
cd: cd,
|
||||
check: check,
|
||||
cls: () => this.clear(),
|
||||
clear: () => this.clear(),
|
||||
cls: () => this.clear(),
|
||||
connect: connect,
|
||||
download: download,
|
||||
expr: expr,
|
||||
free: free,
|
||||
grow: grow,
|
||||
hack: hack,
|
||||
help: help,
|
||||
home: home,
|
||||
@ -686,12 +745,12 @@ export class Terminal implements ITerminal {
|
||||
rm: rm,
|
||||
run: run,
|
||||
scan: scan,
|
||||
"scan-analyze": scananalyze,
|
||||
scp: scp,
|
||||
sudov: sudov,
|
||||
tail: tail,
|
||||
top: top,
|
||||
unalias: unalias,
|
||||
weaken: weaken,
|
||||
wget: wget,
|
||||
};
|
||||
|
||||
|
44
src/Terminal/commands/grow.ts
Normal file
44
src/Terminal/commands/grow.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { Server } from "../../Server/Server";
|
||||
|
||||
export function grow(
|
||||
terminal: ITerminal,
|
||||
router: IRouter,
|
||||
player: IPlayer,
|
||||
server: BaseServer,
|
||||
args: (string | number)[],
|
||||
): void {
|
||||
if (args.length !== 0) {
|
||||
terminal.error("Incorrect usage of grow command. Usage: grow");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error(
|
||||
"Cannot grow your own machines! You are currently connected to your home PC or one of your purchased servers",
|
||||
);
|
||||
}
|
||||
const normalServer = server as Server;
|
||||
// Hack the current PC (usually for money)
|
||||
// You can't grow your home pc or servers you purchased
|
||||
if (normalServer.purchasedByPlayer) {
|
||||
terminal.error(
|
||||
"Cannot grow your own machines! You are currently connected to your home PC or one of your purchased servers",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!normalServer.hasAdminRights) {
|
||||
terminal.error("You do not have admin rights for this machine! Cannot grow");
|
||||
return;
|
||||
}
|
||||
if (normalServer.requiredHackingSkill > player.hacking_skill) {
|
||||
terminal.error(
|
||||
"Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill",
|
||||
);
|
||||
return;
|
||||
}
|
||||
terminal.startGrow(player);
|
||||
}
|
44
src/Terminal/commands/weaken.ts
Normal file
44
src/Terminal/commands/weaken.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { Server } from "../../Server/Server";
|
||||
|
||||
export function weaken(
|
||||
terminal: ITerminal,
|
||||
router: IRouter,
|
||||
player: IPlayer,
|
||||
server: BaseServer,
|
||||
args: (string | number)[],
|
||||
): void {
|
||||
if (args.length !== 0) {
|
||||
terminal.error("Incorrect usage of weaken command. Usage: weaken");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error(
|
||||
"Cannot weaken your own machines! You are currently connected to your home PC or one of your purchased servers",
|
||||
);
|
||||
}
|
||||
const normalServer = server as Server;
|
||||
// Hack the current PC (usually for money)
|
||||
// You can't weaken your home pc or servers you purchased
|
||||
if (normalServer.purchasedByPlayer) {
|
||||
terminal.error(
|
||||
"Cannot weaken your own machines! You are currently connected to your home PC or one of your purchased servers",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!normalServer.hasAdminRights) {
|
||||
terminal.error("You do not have admin rights for this machine! Cannot weaken");
|
||||
return;
|
||||
}
|
||||
if (normalServer.requiredHackingSkill > player.hacking_skill) {
|
||||
terminal.error(
|
||||
"Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill",
|
||||
);
|
||||
return;
|
||||
}
|
||||
terminal.startWeaken(player);
|
||||
}
|
@ -21,6 +21,7 @@ const commands = [
|
||||
"download",
|
||||
"expr",
|
||||
"free",
|
||||
"grow",
|
||||
"hack",
|
||||
"help",
|
||||
"home",
|
||||
@ -36,13 +37,14 @@ const commands = [
|
||||
"ps",
|
||||
"rm",
|
||||
"run",
|
||||
"scan",
|
||||
"scan-analyze",
|
||||
"scan",
|
||||
"scp",
|
||||
"sudov",
|
||||
"tail",
|
||||
"theme",
|
||||
"top",
|
||||
"weaken",
|
||||
];
|
||||
|
||||
export function determineAllPossibilitiesForTabCompletion(
|
||||
|
@ -4,7 +4,7 @@ import { Theme } from "@mui/material/styles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { ITerminal } from "../ITerminal";
|
||||
@ -18,7 +18,6 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
textfield: {
|
||||
margin: theme.spacing(0),
|
||||
width: "100%",
|
||||
},
|
||||
input: {
|
||||
backgroundColor: "#000",
|
||||
@ -330,40 +329,46 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
|
||||
|
||||
return (
|
||||
<>
|
||||
{possibilities.length > 0 && (
|
||||
<Paper square>
|
||||
<Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}>
|
||||
Possible autocomplete candidate:
|
||||
</Typography>
|
||||
<Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}>
|
||||
{possibilities.join(" ")}
|
||||
</Typography>
|
||||
</Paper>
|
||||
)}
|
||||
<TextField
|
||||
color={terminal.action === null ? "primary" : "secondary"}
|
||||
autoFocus
|
||||
disabled={terminal.action !== null}
|
||||
autoComplete="off"
|
||||
classes={{ root: classes.textfield }}
|
||||
value={value}
|
||||
onChange={handleValueChange}
|
||||
inputRef={terminalInput}
|
||||
InputProps={{
|
||||
// for players to hook in
|
||||
id: "terminal-input",
|
||||
className: classes.input,
|
||||
startAdornment: (
|
||||
<Tooltip
|
||||
title={
|
||||
possibilities.length > 0 ? (
|
||||
<>
|
||||
<Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}>
|
||||
Possible autocomplete candidate:
|
||||
</Typography>
|
||||
<Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}>
|
||||
{possibilities.join(" ")}
|
||||
</Typography>
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)
|
||||
}
|
||||
>
|
||||
<TextField
|
||||
fullWidth
|
||||
color={terminal.action === null ? "primary" : "secondary"}
|
||||
autoFocus
|
||||
disabled={terminal.action !== null}
|
||||
autoComplete="off"
|
||||
value={value}
|
||||
classes={{ root: classes.textfield }}
|
||||
onChange={handleValueChange}
|
||||
inputRef={terminalInput}
|
||||
InputProps={{
|
||||
// for players to hook in
|
||||
id: "terminal-input",
|
||||
className: classes.input,
|
||||
startAdornment: (
|
||||
<Typography color={terminal.action === null ? "primary" : "secondary"} flexShrink={0}>
|
||||
[{player.getCurrentServer().hostname} ~{terminal.cwd()}]>
|
||||
</Typography>
|
||||
</>
|
||||
),
|
||||
spellCheck: false,
|
||||
onKeyDown: onKeyDown,
|
||||
}}
|
||||
></TextField>
|
||||
),
|
||||
spellCheck: false,
|
||||
onKeyDown: onKeyDown,
|
||||
}}
|
||||
></TextField>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { dialogBoxCreate } from "./ui/React/DialogBox";
|
||||
import { BaseServer } from "./Server/BaseServer";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "./utils/JSONReviver";
|
||||
@ -47,7 +46,7 @@ export class TextFile {
|
||||
a.download = this.fn;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(() => {
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
|
@ -15,6 +15,7 @@ import { Factions, initFactions } from "./Faction/Factions";
|
||||
import { staneksGift } from "./CotMG/Helper";
|
||||
import { processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
import { SetupTextEditor } from "./ScriptEditor/ui/Root";
|
||||
|
||||
import {
|
||||
getHackingWorkRepGain,
|
||||
@ -45,7 +46,7 @@ import { Reputation } from "./ui/React/Reputation";
|
||||
import { AlertEvents } from "./ui/React/AlertManager";
|
||||
import { exceptionAlert } from "./utils/helpers/exceptionAlert";
|
||||
|
||||
import { startTampering } from "./Exploits/tampering";
|
||||
import { startExploits } from "./Exploits/loops";
|
||||
|
||||
import React from "react";
|
||||
|
||||
@ -266,7 +267,7 @@ const Engine: {
|
||||
},
|
||||
|
||||
load: function (saveString) {
|
||||
startTampering();
|
||||
startExploits();
|
||||
// Load game from save or create new game
|
||||
if (loadGame(saveString)) {
|
||||
ThemeEvents.emit();
|
||||
@ -426,6 +427,7 @@ const Engine: {
|
||||
// Start interactive tutorial
|
||||
iTutorialStart();
|
||||
}
|
||||
SetupTextEditor();
|
||||
},
|
||||
|
||||
start: function () {
|
||||
|
@ -285,7 +285,9 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
The amount of money on a server is not limitless. So, if you constantly hack a server and deplete its money,
|
||||
then you will encounter diminishing returns in your hacking.
|
||||
then you will encounter diminishing returns in your hacking. You will need to use{" "}
|
||||
<Typography classes={{ root: classes.textfield }}>{"[n00dles ~/]> grow"}</Typography>
|
||||
and <Typography classes={{ root: classes.textfield }}>{"[n00dles ~/]> weaken"}</Typography>
|
||||
</Typography>
|
||||
),
|
||||
canNext: true,
|
||||
|
@ -42,7 +42,7 @@ export function AlertManager(): React.ReactElement {
|
||||
<>
|
||||
{alerts.length > 0 && (
|
||||
<Modal open={true} onClose={close}>
|
||||
<Box>
|
||||
<Box overflow="scroll" sx={{ overflowWrap: "break-word", whiteSpace: "pre-line" }}>
|
||||
<Typography>{alerts[0].text}</Typography>
|
||||
</Box>
|
||||
</Modal>
|
||||
|
@ -147,7 +147,7 @@ function LogWindow(props: IProps): React.ReactElement {
|
||||
</Box>
|
||||
</Paper>
|
||||
<Paper>
|
||||
<Box maxHeight="25vh" overflow="scroll" sx={{ overflowWrap: "break-word" }}>
|
||||
<Box maxHeight="25vh" overflow="scroll" sx={{ overflowWrap: "break-word", whiteSpace: "pre-line" }}>
|
||||
{props.script.logs.map(
|
||||
(line: string, i: number): JSX.Element => (
|
||||
<Typography key={i}>
|
||||
|
@ -1,5 +0,0 @@
|
||||
// This is a reference to the native setTimeout() function
|
||||
// setTimeout() is used in various places around the game's source code.
|
||||
// This reference is used to make sure that if players alter window.setTimeout()
|
||||
// through NetscriptJS, then the game will still function properly
|
||||
export const setTimeoutRef = window.setTimeout.bind(window);
|
Loading…
Reference in New Issue
Block a user