diff --git a/doc/source/netscript/sleeveapi/getSleeveAugmentations.rst b/doc/source/netscript/sleeveapi/getSleeveAugmentations.rst new file mode 100644 index 000000000..93f584725 --- /dev/null +++ b/doc/source/netscript/sleeveapi/getSleeveAugmentations.rst @@ -0,0 +1,8 @@ +getSleeveAugmentations() Netscript Function +======================================= + +.. js:function:: getSleeveAugmentations(sleeveNumber) + + :param int sleeveNumber: Index of the sleeve to retrieve augmentations from. See :ref:`here ` + + Return a list of augmentation names that this sleeve has installed. diff --git a/doc/source/netscript/sleeveapi/getSleevePurchasableAugs.rst b/doc/source/netscript/sleeveapi/getSleevePurchasableAugs.rst new file mode 100644 index 000000000..e9ee46a54 --- /dev/null +++ b/doc/source/netscript/sleeveapi/getSleevePurchasableAugs.rst @@ -0,0 +1,17 @@ +getSleevePurchasableAugs() Netscript Function +======================================= + +.. js:function:: getSleevePurchasableAugs(sleeveNumber) + + :param int sleeveNumber: Index of the sleeve to retrieve purchasable augmentations from. See :ref:`here ` + + Return a list of augmentations that the player can buy for this sleeve. + +.. code-block:: javascript + + [ + { + name: string, // augmentation name + cost: number, // augmentation cost + } + ] diff --git a/doc/source/netscript/sleeveapi/purchaseSleeveAug.rst b/doc/source/netscript/sleeveapi/purchaseSleeveAug.rst new file mode 100644 index 000000000..31fff9f49 --- /dev/null +++ b/doc/source/netscript/sleeveapi/purchaseSleeveAug.rst @@ -0,0 +1,9 @@ +purchaseSleeveAug() Netscript Function +======================================= + +.. js:function:: purchaseSleeveAug(sleeveNumber, augName) + + :param int sleeveNumber: Index of the sleeve to buy an aug for. See :ref:`here ` + :param string augName: Name of the aug to buy. See :ref:`here ` + + Return true if the aug was purchased and installed on the sleeve. \ No newline at end of file diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index 6d246a1d2..1e5fb2166 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -73,7 +73,8 @@ import {WorkerScript, workerScripts, import {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript} from "./NetscriptEvaluator"; import {NetscriptPort} from "./NetscriptPort"; -import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum" +import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum"; +import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/Sleeve"; import {Page, routing} from "./ui/navigationTracking"; import {numeralWrapper} from "./ui/numeralFormat"; @@ -5080,6 +5081,70 @@ function NetscriptFunctions(workerScript) { workRepGain: sl.getRepGain(), } }, + getSleeveAugmentations : function(sleeveNumber=0) { + if (workerScript.checkingRam) { + return updateStaticRam("getSleeveAugmentations", CONSTANTS.ScriptSleeveBaseRamCost); + } + if (Player.bitNodeN !== 10 && !SourceFileFlags[10]) { + throw makeRuntimeRejectMsg(workerScript, "getSleeveAugmentations() failed because 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"); + } + updateDynamicRam("getSleeveAugmentations", CONSTANTS.ScriptSleeveBaseRamCost); + if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) { + workerScript.log(`ERROR: sleeve.getSleeveAugmentations(${sleeveNumber}) failed because it is an invalid sleeve number.`); + return []; + } + + 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=0) { + if (workerScript.checkingRam) { + return updateStaticRam("getSleevePurchasableAugs", CONSTANTS.ScriptSleeveBaseRamCost); + } + if (Player.bitNodeN !== 10 && !SourceFileFlags[10]) { + throw makeRuntimeRejectMsg(workerScript, "getSleevePurchasableAugs() failed because 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"); + } + updateDynamicRam("getSleevePurchasableAugs", CONSTANTS.ScriptSleeveBaseRamCost); + if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) { + workerScript.log(`ERROR: sleeve.getSleevePurchasableAugs(${sleeveNumber}) failed because it is an invalid sleeve number.`); + return []; + } + + 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=0, augName="") { + if (workerScript.checkingRam) { + return updateStaticRam("purchaseSleeveAug", CONSTANTS.ScriptSleeveBaseRamCost); + } + if (Player.bitNodeN !== 10 && !SourceFileFlags[10]) { + throw makeRuntimeRejectMsg(workerScript, "purchaseSleeveAug() failed because 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"); + } + updateDynamicRam("purchaseSleeveAug", CONSTANTS.ScriptSleeveBaseRamCost); + if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) { + workerScript.log(`ERROR: sleeve.purchaseSleeveAug(${sleeveNumber}) failed because it is an invalid sleeve number.`); + return false; + } + + const aug = Augmentations[augName]; + if (!aug) { + workerScript.log(`ERROR: sleeve.purchaseSleeveAug(${sleeveNumber}) failed because ${augName} is not a valid aug.`); + } + + return Player.sleeves[sleeveNumber].tryBuyAugmentation(Player, aug); + } } // End sleeve } //End return } //End NetscriptFunction() diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index 6f5a27c98..6fe7f980a 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -14,6 +14,8 @@ import { Person, createTaskTracker } from "../Person"; import { Augmentation } from "../../Augmentation/Augmentation"; +import { Augmentations } from "../../Augmentation/Augmentations"; +import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; @@ -806,6 +808,16 @@ export class Sleeve extends Person { return true; } + tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean { + if (!p.canAfford(aug.startingCost)) { + return false; + } + + p.loseMoney(aug.startingCost); + this.installAugmentation(aug); + return true; + } + /** * Serialize the current object to a JSON save state. */ @@ -814,4 +826,31 @@ export class Sleeve extends Person { } } +export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentation[] { + // You can only purchase Augmentations that are actually available from + // your factions. I.e. you must be in a faction that has the Augmentation + // and you must also have enough rep in that faction in order to purchase it. + + const ownedAugNames: string[] = sleeve.augmentations.map((e) => {return e.name}); + const availableAugs: Augmentation[] = []; + + for (const facName of p.factions) { + if (facName === "Bladeburners") { continue; } + const fac: Faction | null = Factions[facName]; + if (fac == null) { continue; } + + for (const augName of fac.augmentations) { + if (augName === AugmentationNames.NeuroFluxGovernor) { continue; } + if (ownedAugNames.includes(augName)) { continue; } + const aug: Augmentation | null = Augmentations[augName]; + + if (fac.playerReputation > aug.baseRepRequirement && !availableAugs.includes(aug)) { + availableAugs.push(aug); + } + } + } + + return availableAugs; +} + Reviver.constructors.Sleeve = Sleeve; diff --git a/src/PersonObjects/Sleeve/SleeveAugmentationsUI.ts b/src/PersonObjects/Sleeve/SleeveAugmentationsUI.ts index 471d95695..1c7e42ad4 100644 --- a/src/PersonObjects/Sleeve/SleeveAugmentationsUI.ts +++ b/src/PersonObjects/Sleeve/SleeveAugmentationsUI.ts @@ -2,7 +2,7 @@ * Module for handling the UI for purchasing Sleeve Augmentations * This UI is a popup, not a full page */ -import { Sleeve } from "./Sleeve"; +import { Sleeve, findSleevePurchasableAugs } from "./Sleeve"; import { IPlayer } from "../IPlayer"; @@ -29,23 +29,7 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer) { // You can only purchase Augmentations that are actually available from // your factions. I.e. you must be in a faction that has the Augmentation // and you must also have enough rep in that faction in order to purchase it. - const availableAugs: Augmentation[] = []; - - for (const facName of p.factions) { - if (facName === "Bladeburners") { continue; } - const fac: Faction | null = Factions[facName]; - if (fac == null) { continue; } - - for (const augName of fac.augmentations) { - if (augName === AugmentationNames.NeuroFluxGovernor) { continue; } - if (ownedAugNames.includes(augName)) { continue; } - const aug: Augmentation | null = Augmentations[augName]; - - if (fac.playerReputation > aug.baseRepRequirement && !availableAugs.includes(aug)) { - availableAugs.push(aug); - } - } - } + const availableAugs = findSleevePurchasableAugs(sleeve, p); // Create popup const popupId = "purchase-sleeve-augs-popup"; @@ -110,10 +94,8 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer) { ].join(" "), padding: "2px", clickListener: () => { - if (p.canAfford(aug.startingCost)) { - p.loseMoney(aug.startingCost); - sleeve.installAugmentation(aug); - dialogBoxCreate(`Installed ${aug.name} on Duplicate Sleeve!`, false) + if (sleeve.tryBuyAugmentation(p, aug)) { + dialogBoxCreate(`Installed ${aug.name} on Duplicate Sleeve!`, false); removeElementById(popupId); createSleevePurchaseAugsPopup(sleeve, p); } else { diff --git a/src/ScriptEditor/AceNetscriptMode.js b/src/ScriptEditor/AceNetscriptMode.js index 18ca0030a..15873e07c 100644 --- a/src/ScriptEditor/AceNetscriptMode.js +++ b/src/ScriptEditor/AceNetscriptMode.js @@ -128,9 +128,10 @@ let NetscriptFunctions = "getNumTriesRemaining|" + // Sleeve API - "sleeve|getNumSleeves|setToShockRecovery|setToSynchronize|setToCommitCrime|" + - "setToUniversityCourse|travel|setToCompanyWork|setToFactionWork|setToGymWorkout|" + - "getSleeveStats|getTask|getInformation"; + "sleeve|getNumSleeves|setToShockRecovery|setToSynchronize|" + + "setToCommitCrime|setToUniversityCourse|travel|setToCompanyWork|" + + "setToFactionWork|setToGymWorkout|getSleeveStats|getTask|getInformation|" + + "getSleeveAugmentations|getSleevePurchasableAugs|purchaseSleeveAug"; var NetscriptHighlightRules = function(options) { var keywordMapper = this.createKeywordMapper({ diff --git a/src/ScriptEditor/CodeMirrorNetscriptMode.js b/src/ScriptEditor/CodeMirrorNetscriptMode.js index bf6f2790b..fed212ac8 100644 --- a/src/ScriptEditor/CodeMirrorNetscriptMode.js +++ b/src/ScriptEditor/CodeMirrorNetscriptMode.js @@ -257,6 +257,9 @@ CodeMirror.defineMode("netscript", function(config, parserConfig) { "getSleeveStats": atom, "getTask": atom, "getInformation": atom, + "getSleeveAugmentations": atom, + "getSleevePurchasableAugs": atom, + "purchaseSleeveAug": atom, }; }();