made static ram cost typecheck that it's missing no property.

This commit is contained in:
Olivier Gagnon 2022-05-24 18:34:00 -04:00
parent 0da2e74d12
commit ae38b11ede
4 changed files with 154 additions and 56 deletions

@ -18,7 +18,7 @@ type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: Netscri
export type InternalAPI<API> = { export type InternalAPI<API> = {
[Property in keyof API]: API[Property] extends ExternalFunction [Property in keyof API]: API[Property] extends ExternalFunction
? InternalFunction<API[Property]> ? InternalFunction<API[Property]>
: API[Property] extends ExternalAPI : API[Property] extends object
? InternalAPI<API[Property]> ? InternalAPI<API[Property]>
: never; : never;
}; };

@ -1,6 +1,18 @@
import { IPlayer } from "src/PersonObjects/IPlayer"; import { IPlayer } from "src/PersonObjects/IPlayer";
import { IMap } from "../types"; import { IMap } from "../types";
import { NS as INS } from "../ScriptEditor/NetscriptDefinitions";
import { INetscriptExtra } from "../NetscriptFunctions/Extra";
type RamCostTree<API> = {
[Property in keyof API]: API[Property] extends () => void
? number | ((p: IPlayer) => void)
: API[Property] extends object
? RamCostTree<API[Property]>
: never;
};
// TODO remember to update RamCalculations.js and WorkerScript.js // TODO remember to update RamCalculations.js and WorkerScript.js
// RAM costs for Netscript functions // RAM costs for Netscript functions
@ -89,7 +101,7 @@ function SF4Cost(cost: number): (player: IPlayer) => number {
} }
// Hacknet API // Hacknet API
const hacknet: IMap<any> = { const hacknet = {
numNodes: 0, numNodes: 0,
purchaseNode: 0, purchaseNode: 0,
getPurchaseNodeCost: 0, getPurchaseNodeCost: 0,
@ -106,10 +118,15 @@ const hacknet: IMap<any> = {
hashCost: 0, hashCost: 0,
spendHashes: 0, spendHashes: 0,
maxNumNodes: 0, maxNumNodes: 0,
hashCapacity: 0,
getHashUpgrades: 0,
getHashUpgradeLevel: 0,
getStudyMult: 0,
getTrainingMult: 0,
}; };
// Stock API // Stock API
const stock: IMap<any> = { const stock = {
getSymbols: RamCostConstants.ScriptGetStockRamCost, getSymbols: RamCostConstants.ScriptGetStockRamCost,
getPrice: RamCostConstants.ScriptGetStockRamCost, getPrice: RamCostConstants.ScriptGetStockRamCost,
getAskPrice: RamCostConstants.ScriptGetStockRamCost, getAskPrice: RamCostConstants.ScriptGetStockRamCost,
@ -134,7 +151,7 @@ const stock: IMap<any> = {
}; };
// Singularity API // Singularity API
const singularity: IMap<any> = { const singularity = {
universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
@ -190,7 +207,7 @@ const singularity: IMap<any> = {
}; };
// Gang API // Gang API
const gang: IMap<any> = { const gang = {
createGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, createGang: RamCostConstants.ScriptGangApiBaseRamCost / 4,
inGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, inGang: RamCostConstants.ScriptGangApiBaseRamCost / 4,
getMemberNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, getMemberNames: RamCostConstants.ScriptGangApiBaseRamCost / 4,
@ -215,7 +232,7 @@ const gang: IMap<any> = {
}; };
// Bladeburner API // Bladeburner API
const bladeburner: IMap<any> = { const bladeburner = {
getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
@ -253,15 +270,13 @@ const bladeburner: IMap<any> = {
getBonusTime: 0, getBonusTime: 0,
}; };
const infiltration: IMap<any> = { const infiltration = {
calculateDifficulty: RamCostConstants.ScriptInfiltrationCalculateDifficulty, getPossibleLocations: RamCostConstants.ScriptInfiltrationGetLocations,
calculateRewards: RamCostConstants.ScriptInfiltrationCalculateRewards, getInfiltration: RamCostConstants.ScriptInfiltrationGetInfiltrations,
calculateGetLocations: RamCostConstants.ScriptInfiltrationGetLocations,
calculateGetInfiltrations: RamCostConstants.ScriptInfiltrationGetInfiltrations,
}; };
// Coding Contract API // Coding Contract API
const codingcontract: IMap<any> = { const codingcontract = {
attempt: RamCostConstants.ScriptCodingContractBaseRamCost, attempt: RamCostConstants.ScriptCodingContractBaseRamCost,
getContractType: RamCostConstants.ScriptCodingContractBaseRamCost / 2, getContractType: RamCostConstants.ScriptCodingContractBaseRamCost / 2,
getData: RamCostConstants.ScriptCodingContractBaseRamCost / 2, getData: RamCostConstants.ScriptCodingContractBaseRamCost / 2,
@ -270,7 +285,7 @@ const codingcontract: IMap<any> = {
}; };
// Duplicate Sleeve API // Duplicate Sleeve API
const sleeve: IMap<any> = { const sleeve = {
getNumSleeves: RamCostConstants.ScriptSleeveBaseRamCost, getNumSleeves: RamCostConstants.ScriptSleeveBaseRamCost,
setToShockRecovery: RamCostConstants.ScriptSleeveBaseRamCost, setToShockRecovery: RamCostConstants.ScriptSleeveBaseRamCost,
setToSynchronize: RamCostConstants.ScriptSleeveBaseRamCost, setToSynchronize: RamCostConstants.ScriptSleeveBaseRamCost,
@ -290,7 +305,7 @@ const sleeve: IMap<any> = {
}; };
// Stanek API // Stanek API
const stanek: IMap<any> = { const stanek = {
giftWidth: RamCostConstants.ScriptStanekWidth, giftWidth: RamCostConstants.ScriptStanekWidth,
giftHeight: RamCostConstants.ScriptStanekHeight, giftHeight: RamCostConstants.ScriptStanekHeight,
chargeFragment: RamCostConstants.ScriptStanekCharge, chargeFragment: RamCostConstants.ScriptStanekCharge,
@ -305,7 +320,7 @@ const stanek: IMap<any> = {
}; };
// UI API // UI API
const ui: IMap<any> = { const ui = {
getTheme: 0, getTheme: 0,
setTheme: 0, setTheme: 0,
resetTheme: 0, resetTheme: 0,
@ -313,17 +328,84 @@ const ui: IMap<any> = {
setStyles: 0, setStyles: 0,
resetStyles: 0, resetStyles: 0,
getGameInfo: 0, getGameInfo: 0,
clearTerminal: 0,
}; };
// Grafting API // Grafting API
const grafting: IMap<any> = { const grafting = {
getAugmentationGraftPrice: 3.75, getAugmentationGraftPrice: 3.75,
getAugmentationGraftTime: 3.75, getAugmentationGraftTime: 3.75,
getGraftableAugmentations: 5, getGraftableAugmentations: 5,
graftAugmentation: 7.5, graftAugmentation: 7.5,
}; };
export const RamCosts: IMap<any> = { const corporation = {
createCorporation: 0,
hasUnlockUpgrade: 0,
getUnlockUpgradeCost: 0,
getUpgradeLevel: 0,
getUpgradeLevelCost: 0,
getExpandIndustryCost: 0,
getExpandCityCost: 0,
getInvestmentOffer: 0,
acceptInvestmentOffer: 0,
goPublic: 0,
bribe: 0,
getCorporation: 0,
getDivision: 0,
expandIndustry: 0,
expandCity: 0,
unlockUpgrade: 0,
levelUpgrade: 0,
issueDividends: 0,
buyBackShares: 0,
sellShares: 0,
getBonusTime: 0,
sellMaterial: 0,
sellProduct: 0,
discontinueProduct: 0,
setSmartSupply: 0,
setSmartSupplyUseLeftovers: 0,
buyMaterial: 0,
bulkPurchase: 0,
getWarehouse: 0,
getProduct: 0,
getMaterial: 0,
setMaterialMarketTA1: 0,
setMaterialMarketTA2: 0,
setProductMarketTA1: 0,
setProductMarketTA2: 0,
exportMaterial: 0,
cancelExportMaterial: 0,
purchaseWarehouse: 0,
upgradeWarehouse: 0,
makeProduct: 0,
limitMaterialProduction: 0,
limitProductProduction: 0,
getPurchaseWarehouseCost: 0,
getUpgradeWarehouseCost: 0,
hasWarehouse: 0,
assignJob: 0,
hireEmployee: 0,
upgradeOfficeSize: 0,
throwParty: 0,
buyCoffee: 0,
hireAdVert: 0,
research: 0,
getOffice: 0,
getEmployee: 0,
getHireAdVertCost: 0,
getHireAdVertCount: 0,
getResearchCost: 0,
hasResearched: 0,
setAutoJobAssignment: 0,
getOfficeSizeUpgradeCost: 0,
};
const SourceRamCosts = {
args: undefined as unknown as never[], // special use case
enums: undefined as unknown as never,
corporation,
hacknet, hacknet,
stock, stock,
singularity, singularity,
@ -363,7 +445,6 @@ export const RamCosts: IMap<any> = {
enableLog: 0, enableLog: 0,
isLogEnabled: 0, isLogEnabled: 0,
getScriptLogs: 0, getScriptLogs: 0,
clearTerminal: RamCostConstants.ScriptClearTerminalCost,
nuke: RamCostConstants.ScriptPortProgramRamCost, nuke: RamCostConstants.ScriptPortProgramRamCost,
brutessh: RamCostConstants.ScriptPortProgramRamCost, brutessh: RamCostConstants.ScriptPortProgramRamCost,
ftpcrack: RamCostConstants.ScriptPortProgramRamCost, ftpcrack: RamCostConstants.ScriptPortProgramRamCost,
@ -382,7 +463,6 @@ export const RamCosts: IMap<any> = {
ps: RamCostConstants.ScriptScanRamCost, ps: RamCostConstants.ScriptScanRamCost,
getRecentScripts: RamCostConstants.ScriptRecentScriptsRamCost, getRecentScripts: RamCostConstants.ScriptRecentScriptsRamCost,
hasRootAccess: RamCostConstants.ScriptHasRootAccessRamCost, hasRootAccess: RamCostConstants.ScriptHasRootAccessRamCost,
getIp: RamCostConstants.ScriptGetHostnameRamCost,
getHostname: RamCostConstants.ScriptGetHostnameRamCost, getHostname: RamCostConstants.ScriptGetHostnameRamCost,
getHackingLevel: RamCostConstants.ScriptGetHackingLevelRamCost, getHackingLevel: RamCostConstants.ScriptGetHackingLevelRamCost,
getHackingMultipliers: RamCostConstants.ScriptGetMultipliersRamCost, getHackingMultipliers: RamCostConstants.ScriptGetMultipliersRamCost,
@ -439,6 +519,15 @@ export const RamCosts: IMap<any> = {
getOwnedSourceFiles: RamCostConstants.ScriptGetOwnedSourceFiles, getOwnedSourceFiles: RamCostConstants.ScriptGetOwnedSourceFiles,
tail: 0, tail: 0,
toast: 0, toast: 0,
closeTail: 0,
clearPort: 0,
openDevMenu: 0,
alert: 0,
flags: 0,
exploit: 0,
bypass: 0,
alterReality: 0,
rainbow: 0,
heart: { heart: {
// Easter egg function // Easter egg function
break: 0, break: 0,
@ -492,6 +581,12 @@ export const RamCosts: IMap<any> = {
}, },
}; };
export const RamCosts: IMap<any> = SourceRamCosts;
// This line in particular is there so typescript typechecks that we are not missing any static ram cost.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _typecheck: RamCostTree<INS & INetscriptExtra> = SourceRamCosts;
export function getRamCost(player: IPlayer, ...args: string[]): number { export function getRamCost(player: IPlayer, ...args: string[]): number {
if (args.length === 0) { if (args.length === 0) {
console.warn(`No arguments passed to getRamCost()`); console.warn(`No arguments passed to getRamCost()`);

@ -62,7 +62,7 @@ import { isString } from "./utils/helpers/isString";
import { BaseServer } from "./Server/BaseServer"; import { BaseServer } from "./Server/BaseServer";
import { NetscriptGang } from "./NetscriptFunctions/Gang"; import { NetscriptGang } from "./NetscriptFunctions/Gang";
import { NetscriptSleeve } from "./NetscriptFunctions/Sleeve"; import { NetscriptSleeve } from "./NetscriptFunctions/Sleeve";
import { NetscriptExtra } from "./NetscriptFunctions/Extra"; import { NetscriptExtra, INetscriptExtra } from "./NetscriptFunctions/Extra";
import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet"; import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet";
import { NetscriptStanek } from "./NetscriptFunctions/Stanek"; import { NetscriptStanek } from "./NetscriptFunctions/Stanek";
import { NetscriptInfiltration } from "./NetscriptFunctions/Infiltration"; import { NetscriptInfiltration } from "./NetscriptFunctions/Infiltration";
@ -532,7 +532,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}, },
}; };
const extra = NetscriptExtra(Player, workerScript, helper); const extra = wrapAPI(helper, {}, workerScript, NetscriptExtra(Player)) as unknown as INetscriptExtra;
const formulas = wrapAPI(helper, {}, workerScript, NetscriptFormulas(Player, helper), "formulas") const formulas = wrapAPI(helper, {}, workerScript, NetscriptFormulas(Player, helper), "formulas")
.formulas as unknown as IFormulas; .formulas as unknown as IFormulas;

@ -1,9 +1,8 @@
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { Exploit } from "../Exploits/Exploit"; import { Exploit } from "../Exploits/Exploit";
import * as bcrypt from "bcryptjs"; import * as bcrypt from "bcryptjs";
import { INetscriptHelper } from "./INetscriptHelper";
import { Apr1Events as devMenu } from "../ui/Apr1"; import { Apr1Events as devMenu } from "../ui/Apr1";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
export interface INetscriptExtra { export interface INetscriptExtra {
heart: { heart: {
@ -16,35 +15,37 @@ export interface INetscriptExtra {
rainbow(guess: string): void; rainbow(guess: string): void;
} }
export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): INetscriptExtra { export function NetscriptExtra(player: IPlayer): InternalAPI<INetscriptExtra> {
return { return {
heart: { heart: {
// Easter egg function // Easter egg function
break: function (): number { break: () => (): number => {
return player.karma; return player.karma;
}, },
}, },
openDevMenu: function (): void { openDevMenu: () => (): void => {
devMenu.emit(); devMenu.emit();
}, },
exploit: function (): void { exploit: () => (): void => {
player.giveExploit(Exploit.UndocumentedFunctionCall); player.giveExploit(Exploit.UndocumentedFunctionCall);
}, },
bypass: function (doc: unknown): void { bypass:
// reset both fields first (ctx: NetscriptContext) =>
const d = doc as any; (doc: unknown): void => {
d.completely_unused_field = undefined; // reset both fields first
const real_document: any = document; const d = doc as any;
real_document.completely_unused_field = undefined; d.completely_unused_field = undefined;
// set one to true and check that it affected the other. const real_document: any = document;
real_document.completely_unused_field = true; real_document.completely_unused_field = undefined;
if (d.completely_unused_field && workerScript.ramUsage === 1.6) { // set one to true and check that it affected the other.
player.giveExploit(Exploit.Bypass); real_document.completely_unused_field = true;
} if (d.completely_unused_field && ctx.workerScript.ramUsage === 1.6) {
d.completely_unused_field = undefined; player.giveExploit(Exploit.Bypass);
real_document.completely_unused_field = undefined; }
}, d.completely_unused_field = undefined;
alterReality: function (): void { real_document.completely_unused_field = undefined;
},
alterReality: () => (): void => {
// We need to trick webpack into not optimizing a variable that is guaranteed to be false (and doesn't use prototypes) // We need to trick webpack into not optimizing a variable that is guaranteed to be false (and doesn't use prototypes)
let x = false; let x = false;
const recur = function (depth: number): void { const recur = function (depth: number): void {
@ -59,20 +60,22 @@ export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, help
player.giveExploit(Exploit.RealityAlteration); player.giveExploit(Exploit.RealityAlteration);
} }
}, },
rainbow: function (guess: unknown): boolean { rainbow:
function tryGuess(): boolean { (ctx: NetscriptContext) =>
// eslint-disable-next-line no-sync (guess: unknown): boolean => {
const verified = bcrypt.compareSync( function tryGuess(): boolean {
helper.string("rainbow", "guess", guess), // eslint-disable-next-line no-sync
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO", const verified = bcrypt.compareSync(
); ctx.helper.string("guess", guess),
if (verified) { "$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO",
player.giveExploit(Exploit.INeedARainbow); );
return true; if (verified) {
player.giveExploit(Exploit.INeedARainbow);
return true;
}
return false;
} }
return false; return tryGuess();
} },
return tryGuess();
},
}; };
} }