namespaced formulas for easier importing
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
a6a00066cc
commit
f12de39c91
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
NOTE: All user scripts to be synced with the game is found under `src/`.
|
||||
|
||||
## TODO
|
||||
|
||||
- Fix the fucking ezgame.formulas.hacking.growTime(). calculateIntelligenceBonus() is throwing errors when calculating intelligence. Clearly my intelligence value is 0.
|
||||
|
||||
This is a template for a viteburner project. It is a simple example of how to use Viteburner.
|
||||
|
||||
## How to use
|
||||
|
|
|
|||
5
src/ezgame.ts
Normal file
5
src/ezgame.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { formulas } from "./ezgame/formulas";
|
||||
|
||||
export const ezgame = {
|
||||
formulas,
|
||||
};
|
||||
15
src/ezgame/formulas.ts
Normal file
15
src/ezgame/formulas.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { gang } from "./formulas/gang";
|
||||
import { hacking } from "./formulas/hacking";
|
||||
import { hacknetNodes } from "./formulas/hacknet-nodes";
|
||||
import { hacknetServers } from "./formulas/hacknet-servers";
|
||||
import { reputation } from "./formulas/reputation";
|
||||
import { skills } from "./formulas/skills";
|
||||
|
||||
export const formulas = {
|
||||
gang,
|
||||
hacking,
|
||||
hacknetNodes,
|
||||
hacknetServers,
|
||||
reputation,
|
||||
skills,
|
||||
};
|
||||
|
|
@ -6,7 +6,7 @@ Reverse engineered from the [bitburner source](https://github.com/bitburner-offi
|
|||
|
||||
### Gang
|
||||
|
||||
- [ ] `ascencionMultipler(points)`
|
||||
- [ ] `ascensionMultiplier(points)`
|
||||
- [ ] `ascensionPointsGain(exp)`
|
||||
- [ ] `moneyGain(gang, member, task)`
|
||||
- [ ] `respectGain(gang, member, task)`
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { Multipliers } from "@ns";
|
||||
import { PartialRecord } from "./exports";
|
||||
|
||||
/**
|
||||
* Generic Game Constants
|
||||
|
|
@ -210,3 +211,4 @@ export const MaxFavor = 35331;
|
|||
// This is the nearest representable value of log(1.02), which is the base of our power.
|
||||
// It is *not* the same as Math.log(1.02), since "1.02" lacks sufficient precision.
|
||||
export const log1point02 = 0.019802627296179712;
|
||||
export const getRecordEntries = Object.entries as <K extends string, V>(record: PartialRecord<K, V>) => [K, V][];
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
import { clampNumber } from "./utils";
|
||||
import { clampNumber } from "@/utils/utils";
|
||||
import { getRecordEntries } from "./constants";
|
||||
|
||||
export type PartialRecord<K extends string, V> = Partial<Record<K, V>>;
|
||||
export const getRecordEntries = Object.entries as <K extends string, V>(record: PartialRecord<K, V>) => [K, V][];
|
||||
|
||||
/**
|
||||
* Bitnode multipliers influence the difficulty of different aspects of the game.
|
||||
* Each Bitnode has a different theme/strategy to achieving the end goal, so these multipliers will can help drive the
|
||||
|
|
@ -1,18 +1,27 @@
|
|||
import { currentNodeMults } from "./exports";
|
||||
|
||||
export interface FormulaGang {
|
||||
export const gang = {
|
||||
ascensionMultiplier: calculateAscensionMult,
|
||||
ascensionPointsGain: calculateAscensionPointsGain,
|
||||
moneyGain: calculateMoneyGain,
|
||||
respectGain: calculateRespectGain,
|
||||
wantedLevelGain: calculateWantedLevelGain,
|
||||
wantedPenalty: calculateWantedPenalty,
|
||||
};
|
||||
|
||||
interface FormulaGang {
|
||||
respect: number;
|
||||
territory: number;
|
||||
wantedLevel: number;
|
||||
}
|
||||
|
||||
export interface ITerritory {
|
||||
interface ITerritory {
|
||||
money: number;
|
||||
respect: number;
|
||||
wanted: number;
|
||||
}
|
||||
|
||||
export interface ITaskParams {
|
||||
interface ITaskParams {
|
||||
baseRespect?: number;
|
||||
baseWanted?: number;
|
||||
baseMoney?: number;
|
||||
|
|
@ -26,7 +35,7 @@ export interface ITaskParams {
|
|||
territory?: ITerritory;
|
||||
}
|
||||
|
||||
export class GangMember {
|
||||
class GangMember {
|
||||
name: string;
|
||||
task = "Unassigned";
|
||||
|
||||
|
|
@ -68,7 +77,7 @@ export class GangMember {
|
|||
}
|
||||
}
|
||||
|
||||
export class GangMemberTask {
|
||||
class GangMemberTask {
|
||||
name: string;
|
||||
desc: string;
|
||||
|
||||
|
|
@ -132,11 +141,11 @@ export class GangMemberTask {
|
|||
}
|
||||
}
|
||||
|
||||
export function calculateWantedPenalty(gang: FormulaGang): number {
|
||||
function calculateWantedPenalty(gang: FormulaGang): number {
|
||||
return gang.respect / (gang.respect + gang.wantedLevel);
|
||||
}
|
||||
|
||||
export function calculateRespectGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||
function calculateRespectGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||
if (task.baseRespect === 0) return 0;
|
||||
let statWeight =
|
||||
(task.hackWeight / 100) * member.hack +
|
||||
|
|
@ -154,7 +163,7 @@ export function calculateRespectGain(gang: FormulaGang, member: GangMember, task
|
|||
return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);
|
||||
}
|
||||
|
||||
export function calculateWantedLevelGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||
function calculateWantedLevelGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||
if (task.baseWanted === 0) return 0;
|
||||
let statWeight =
|
||||
(task.hackWeight / 100) * member.hack +
|
||||
|
|
@ -177,7 +186,7 @@ export function calculateWantedLevelGain(gang: FormulaGang, member: GangMember,
|
|||
return Math.min(100, calc);
|
||||
}
|
||||
|
||||
export function calculateMoneyGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||
function calculateMoneyGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||
if (task.baseMoney === 0) return 0;
|
||||
let statWeight =
|
||||
(task.hackWeight / 100) * member.hack +
|
||||
|
|
@ -196,10 +205,10 @@ export function calculateMoneyGain(gang: FormulaGang, member: GangMember, task:
|
|||
return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);
|
||||
}
|
||||
|
||||
export function calculateAscensionPointsGain(exp: number): number {
|
||||
function calculateAscensionPointsGain(exp: number): number {
|
||||
return Math.max(exp - 1000, 0);
|
||||
}
|
||||
|
||||
export function calculateAscensionMult(points: number): number {
|
||||
function calculateAscensionMult(points: number): number {
|
||||
return Math.max(Math.pow(points / 2000, 0.5), 1);
|
||||
}
|
||||
|
|
@ -1,10 +1,26 @@
|
|||
import { clampNumber, isValidNumber } from "@/utils/utils";
|
||||
import { Player as IPerson, Server as IServer } from "@ns";
|
||||
import { ServerConstants } from "./constants";
|
||||
import { currentNodeMults } from "./exports";
|
||||
import { Player } from "./player";
|
||||
import { clampNumber, isValidNumber } from "./utils";
|
||||
|
||||
export function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
||||
export const hacking = {
|
||||
growAmount: calculateGrowMoney,
|
||||
growPercent: calculateServerGrowth,
|
||||
growThreads,
|
||||
growTime: calculateGrowTime,
|
||||
hackChance: calculateHackingChance,
|
||||
hackExp: calculateHackingExpGain,
|
||||
hackPercent: calculatePercentMoneyHacked,
|
||||
hackTime: calculateHackingTime,
|
||||
weakenTime: calculateWeakenTime,
|
||||
numCycleForGrowthCorrected,
|
||||
calculateServerGrowthLog,
|
||||
numCycleForGrowth,
|
||||
getWeakenEffect,
|
||||
};
|
||||
|
||||
function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
||||
const effectiveIntelligence =
|
||||
Player.bitNodeOptions.intelligenceOverride !== undefined
|
||||
? Math.min(Player.bitNodeOptions.intelligenceOverride, intelligence)
|
||||
|
|
@ -13,7 +29,7 @@ export function calculateIntelligenceBonus(intelligence: number, weight = 1): nu
|
|||
}
|
||||
|
||||
/** Returns the chance the person has to successfully hack a server */
|
||||
export function calculateHackingChance(server: IServer, person: IPerson): number {
|
||||
function calculateHackingChance(server: IServer, person: IPerson): number {
|
||||
const hackDifficulty = server.hackDifficulty ?? 100;
|
||||
const requiredHackingSkill = server.requiredHackingSkill ?? 1e9;
|
||||
// Unrooted or unhackable server
|
||||
|
|
@ -34,7 +50,7 @@ export function calculateHackingChance(server: IServer, person: IPerson): number
|
|||
* Returns the amount of hacking experience the person will gain upon
|
||||
* successfully hacking a server
|
||||
*/
|
||||
export function calculateHackingExpGain(server: IServer, person: IPerson): number {
|
||||
function calculateHackingExpGain(server: IServer, person: IPerson): number {
|
||||
const baseDifficulty = server.baseDifficulty;
|
||||
if (!baseDifficulty) return 0;
|
||||
const baseExpGain = 3;
|
||||
|
|
@ -48,7 +64,7 @@ export function calculateHackingExpGain(server: IServer, person: IPerson): numbe
|
|||
* Returns the percentage of money that will be stolen from a server if
|
||||
* it is successfully hacked (returns the decimal form, not the actual percent value)
|
||||
*/
|
||||
export function calculatePercentMoneyHacked(server: IServer, person: IPerson): number {
|
||||
function calculatePercentMoneyHacked(server: IServer, person: IPerson): number {
|
||||
const hackDifficulty = server.hackDifficulty ?? 100;
|
||||
if (hackDifficulty >= 100) return 0;
|
||||
const requiredHackingSkill = server.requiredHackingSkill ?? 1e9;
|
||||
|
|
@ -64,7 +80,7 @@ export function calculatePercentMoneyHacked(server: IServer, person: IPerson): n
|
|||
}
|
||||
|
||||
/** Returns time it takes to complete a hack on a server, in seconds */
|
||||
export function calculateHackingTime(server: IServer, person: IPerson): number {
|
||||
function calculateHackingTime(server: IServer, person: IPerson): number {
|
||||
const { hackDifficulty, requiredHackingSkill } = server;
|
||||
if (typeof hackDifficulty !== "number" || typeof requiredHackingSkill !== "number") return Infinity;
|
||||
const difficultyMult = requiredHackingSkill * hackDifficulty;
|
||||
|
|
@ -86,21 +102,21 @@ export function calculateHackingTime(server: IServer, person: IPerson): number {
|
|||
}
|
||||
|
||||
/** Returns time it takes to complete a grow operation on a server, in seconds */
|
||||
export function calculateGrowTime(server: IServer, person: IPerson): number {
|
||||
function calculateGrowTime(server: IServer, person: IPerson): number {
|
||||
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
|
||||
|
||||
return growTimeMultiplier * calculateHackingTime(server, person);
|
||||
}
|
||||
|
||||
/** Returns time it takes to complete a weaken operation on a server, in seconds */
|
||||
export function calculateWeakenTime(server: IServer, person: IPerson): number {
|
||||
function calculateWeakenTime(server: IServer, person: IPerson): number {
|
||||
const weakenTimeMultiplier = 4; // Relative to hacking time
|
||||
|
||||
return weakenTimeMultiplier * calculateHackingTime(server, person);
|
||||
}
|
||||
|
||||
// Returns the log of the growth rate. When passing 1 for threads, this gives a useful constant.
|
||||
export function calculateServerGrowthLog(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||
function calculateServerGrowthLog(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||
if (!server.serverGrowth) return -Infinity;
|
||||
const hackDifficulty = server.hackDifficulty ?? 100;
|
||||
const numServerGrowthCycles = Math.max(threads, 0);
|
||||
|
|
@ -123,14 +139,14 @@ export function calculateServerGrowthLog(server: IServer, threads: number, p: IP
|
|||
return adjGrowthLog * serverGrowthPercentageAdjusted * p.mults.hacking_grow * coreBonus * numServerGrowthCycles;
|
||||
}
|
||||
|
||||
export function calculateServerGrowth(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||
function calculateServerGrowth(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||
if (!server.serverGrowth) return 0;
|
||||
return Math.exp(calculateServerGrowthLog(server, threads, p, cores));
|
||||
}
|
||||
|
||||
// This differs from calculateServerGrowth in that it includes the additive
|
||||
// factor and all the boundary checks.
|
||||
export function calculateGrowMoney(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||
function calculateGrowMoney(server: IServer, p: IPerson, threads: number, cores = 1): number {
|
||||
let serverGrowth = calculateServerGrowth(server, threads, p, cores);
|
||||
if (serverGrowth < 1) {
|
||||
console.warn("serverGrowth calculated to be less than 1");
|
||||
|
|
@ -160,27 +176,48 @@ export function calculateGrowMoney(server: IServer, threads: number, p: IPerson,
|
|||
* @param p - Reference to Player object
|
||||
* @returns Number of "growth cycles" needed
|
||||
*/
|
||||
export function numCycleForGrowth(server: IServer, growth: number, cores = 1): number {
|
||||
function numCycleForGrowth(server: IServer, growth: number, cores = 1): number {
|
||||
if (!server.serverGrowth) return Infinity;
|
||||
return Math.log(growth) / calculateServerGrowthLog(server, 1, Player, cores);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper of the function `numCycleForGrowthCorrected`.
|
||||
*
|
||||
* Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable.
|
||||
* Note that when simulating the effect of {@link NS.grow | grow}, what matters is the state of the server and player
|
||||
* when the grow *finishes*, not when it is started.
|
||||
*
|
||||
* The growth amount depends both linearly *and* exponentially on threads; see {@link NS.grow | grow} for more details.
|
||||
*
|
||||
* The inverse of this function is {@link HackingFormulas.growAmount | formulas.hacking.growAmount},
|
||||
* although it can work with fractional threads.
|
||||
* @param server - Server info, typically from {@link NS.getServer | getServer}
|
||||
* @param player - Player info, typically from {@link NS.getPlayer | getPlayer}
|
||||
* @param targetMoney - Desired final money, capped to server's moneyMax
|
||||
* @param cores - Number of cores on the computer that will execute grow.
|
||||
* @returns The calculated grow threads as an integer, rounded up.
|
||||
*/
|
||||
function growThreads(server: IServer, player: IPerson, targetMoney: number, cores = 1): number {
|
||||
return numCycleForGrowthCorrected(server, player, targetMoney, server.moneyAvailable ?? 0, cores);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates the number of threads needed to grow a server from one $amount to a higher $amount
|
||||
* (ie, how many threads to grow this server from $200 to $600 for example).
|
||||
* It protects the inputs (so putting in INFINITY for targetMoney will use moneyMax, putting in a negative for start will use 0, etc.)
|
||||
* @param server - Server being grown
|
||||
* @param targetMoney - How much you want the server grown TO (not by), for instance, to grow from 200 to 600, input 600
|
||||
* @param startMoney - How much you are growing the server from, for instance, to grow from 200 to 600, input 200
|
||||
* @param startMoney - How much you are growing the server from, for instance, to grow from 200 to 600, input 200. Usually this will just be the server's current money `server.available`, but it is a parameter to allow for more flexible use.
|
||||
* @param cores - Number of cores on the host performing grow
|
||||
* @returns Integer threads needed by a single ns.grow call to reach targetMoney from startMoney.
|
||||
*/
|
||||
export function numCycleForGrowthCorrected(
|
||||
function numCycleForGrowthCorrected(
|
||||
server: IServer,
|
||||
person: IPerson = Player,
|
||||
targetMoney: number,
|
||||
startMoney: number,
|
||||
cores = 1,
|
||||
person: IPerson = Player,
|
||||
): number {
|
||||
if (!server.serverGrowth) return Infinity;
|
||||
const moneyMax = server.moneyMax ?? 1;
|
||||
|
|
@ -286,12 +323,12 @@ export function numCycleForGrowthCorrected(
|
|||
return ccycle + 1;
|
||||
}
|
||||
|
||||
export function getCoreBonus(cores = 1): number {
|
||||
function getCoreBonus(cores = 1): number {
|
||||
const coreBonus = 1 + (cores - 1) / 16;
|
||||
return coreBonus;
|
||||
}
|
||||
|
||||
export function getWeakenEffect(threads: number, cores: number): number {
|
||||
function getWeakenEffect(threads: number, cores: number): number {
|
||||
const coreBonus = getCoreBonus(cores);
|
||||
return ServerConstants.ServerWeakenAmount * threads * coreBonus * currentNodeMults.ServerWeakenRate;
|
||||
}
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
import { currentNodeMults } from "./exports";
|
||||
import { HacknetNodeConstants } from "./constants";
|
||||
|
||||
export function calculateMoneyGainRate(level: number, ram: number, cores: number, mult: number): number {
|
||||
export const hacknetNodes = {
|
||||
calculateMoneyGainRate,
|
||||
calculateLevelUpgradeCost,
|
||||
calculateRamUpgradeCost,
|
||||
calculateCoreUpgradeCost,
|
||||
calculateNodeCost,
|
||||
};
|
||||
|
||||
function calculateMoneyGainRate(level: number, ram: number, cores: number, mult: number): number {
|
||||
const gainPerLevel = HacknetNodeConstants.MoneyGainPerLevel;
|
||||
|
||||
const levelMult = level * gainPerLevel;
|
||||
|
|
@ -10,7 +18,7 @@ export function calculateMoneyGainRate(level: number, ram: number, cores: number
|
|||
return levelMult * ramMult * coresMult * mult * currentNodeMults.HacknetNodeMoney;
|
||||
}
|
||||
|
||||
export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
||||
function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
||||
const sanitizedLevels = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
|
|
@ -31,7 +39,7 @@ export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1
|
|||
return HacknetNodeConstants.LevelBaseCost * totalMultiplier * costMult;
|
||||
}
|
||||
|
||||
export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
||||
function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
||||
const sanitizedLevels = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
|
|
@ -60,7 +68,7 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
|
|||
return totalCost;
|
||||
}
|
||||
|
||||
export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
||||
function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
||||
const sanitizedCores = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedCores) || sanitizedCores < 1) {
|
||||
return 0;
|
||||
|
|
@ -84,7 +92,7 @@ export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1,
|
|||
return totalCost;
|
||||
}
|
||||
|
||||
export function calculateNodeCost(n: number, mult = 1): number {
|
||||
function calculateNodeCost(n: number, mult = 1): number {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,13 +1,16 @@
|
|||
import { currentNodeMults } from "./exports";
|
||||
import { HacknetServerConstants } from "./constants";
|
||||
|
||||
export function calculateHashGainRate(
|
||||
level: number,
|
||||
ramUsed: number,
|
||||
maxRam: number,
|
||||
cores: number,
|
||||
mult: number,
|
||||
): number {
|
||||
export const hacknetServers = {
|
||||
calculateHashGainRate,
|
||||
calculateLevelUpgradeCost,
|
||||
calculateRamUpgradeCost,
|
||||
calculateCoreUpgradeCost,
|
||||
calculateCacheUpgradeCost,
|
||||
calculateServerCost,
|
||||
};
|
||||
|
||||
function calculateHashGainRate(level: number, ramUsed: number, maxRam: number, cores: number, mult: number): number {
|
||||
const baseGain = HacknetServerConstants.HashesPerLevel * level;
|
||||
const ramMultiplier = Math.pow(1.07, Math.log2(maxRam));
|
||||
const coreMultiplier = 1 + (cores - 1) / 5;
|
||||
|
|
@ -16,7 +19,7 @@ export function calculateHashGainRate(
|
|||
return baseGain * ramMultiplier * coreMultiplier * ramRatio * mult * currentNodeMults.HacknetNodeMoney;
|
||||
}
|
||||
|
||||
export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
||||
function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
||||
const sanitizedLevels = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
|
|
@ -37,7 +40,7 @@ export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1
|
|||
return 10 * HacknetServerConstants.BaseCost * totalMultiplier * costMult;
|
||||
}
|
||||
|
||||
export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
||||
function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
||||
const sanitizedLevels = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
|
|
@ -64,7 +67,7 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
|
|||
return totalCost;
|
||||
}
|
||||
|
||||
export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
||||
function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
||||
const sanitizedLevels = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
|
|
@ -87,7 +90,7 @@ export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1,
|
|||
return totalCost;
|
||||
}
|
||||
|
||||
export function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1): number {
|
||||
function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1): number {
|
||||
const sanitizedLevels = Math.round(extraLevels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
|
|
@ -111,7 +114,7 @@ export function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1
|
|||
|
||||
// TODO: reverse engineer hashUpgradeCost
|
||||
|
||||
export function calculateServerCost(n: number, mult = 1): number {
|
||||
function calculateServerCost(n: number, mult = 1): number {
|
||||
if (n - 1 >= HacknetServerConstants.MaxServers) {
|
||||
return Infinity;
|
||||
}
|
||||
|
|
@ -1,35 +1,45 @@
|
|||
import { Person as IPerson } from "@ns";
|
||||
import { currentNodeMults } from "./exports";
|
||||
import { clampNumber } from "./utils";
|
||||
import { CONSTANTS, log1point02, MaxFavor } from "./constants";
|
||||
import { Player } from "./player";
|
||||
import { clampNumber } from "@/utils/utils";
|
||||
|
||||
export function favorToRep(f: number): number {
|
||||
export const reputation = {
|
||||
favorToRep,
|
||||
repToFavor,
|
||||
calculateFavorAfterResetting,
|
||||
repFromDonation,
|
||||
donationForRep,
|
||||
repNeededToDonate,
|
||||
canDonate,
|
||||
};
|
||||
|
||||
function favorToRep(f: number): number {
|
||||
// expm1 is e^x - 1, which is more accurate for small x than doing it the obvious way.
|
||||
return clampNumber(25000 * Math.expm1(log1point02 * f), 0);
|
||||
}
|
||||
|
||||
export function repToFavor(r: number): number {
|
||||
function repToFavor(r: number): number {
|
||||
// log1p is log(x + 1), which is more accurate for small x than doing it the obvious way.
|
||||
return clampNumber(Math.log1p(r / 25000) / log1point02, 0, MaxFavor);
|
||||
}
|
||||
|
||||
export function calculateFavorAfterResetting(favor: number, playerReputation: number) {
|
||||
function calculateFavorAfterResetting(favor: number, playerReputation: number) {
|
||||
return repToFavor(favorToRep(favor) + playerReputation);
|
||||
}
|
||||
|
||||
export function repFromDonation(amt: number, person: IPerson): number {
|
||||
function repFromDonation(amt: number, person: IPerson): number {
|
||||
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep * currentNodeMults.FactionWorkRepGain;
|
||||
}
|
||||
|
||||
export function donationForRep(rep: number, person: IPerson): number {
|
||||
function donationForRep(rep: number, person: IPerson): number {
|
||||
return (rep * CONSTANTS.DonateMoneyToRepDivisor) / person.mults.faction_rep / currentNodeMults.FactionWorkRepGain;
|
||||
}
|
||||
|
||||
export function repNeededToDonate(): number {
|
||||
function repNeededToDonate(): number {
|
||||
return Math.floor(CONSTANTS.BaseFavorToDonate * currentNodeMults.RepToDonateToFaction);
|
||||
}
|
||||
|
||||
export function canDonate(amt: number): boolean {
|
||||
function canDonate(amt: number): boolean {
|
||||
return !isNaN(amt) && amt > 0 && Player.money >= amt;
|
||||
}
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
import { clampNumber } from "./utils";
|
||||
import { clampNumber } from "@/utils/utils";
|
||||
|
||||
export const skills = {
|
||||
calculateSkill,
|
||||
calculateExp,
|
||||
calculateSkillProgress,
|
||||
getEmptySkillProgress,
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an experience amount and stat multiplier, calculates the
|
||||
|
|
@ -14,7 +21,7 @@ export function calculateSkill(exp: number, mult = 1): number {
|
|||
return clampNumber(value, 1);
|
||||
}
|
||||
|
||||
export function calculateExp(skill: number, mult = 1): number {
|
||||
function calculateExp(skill: number, mult = 1): number {
|
||||
const floorSkill = Math.floor(skill);
|
||||
let value = Math.exp((skill / mult + 200) / 32) - 534.6;
|
||||
if (skill === floorSkill && Number.isFinite(skill) && Number.isFinite(value)) {
|
||||
|
|
@ -33,7 +40,7 @@ export function calculateExp(skill: number, mult = 1): number {
|
|||
return clampNumber(value, 0);
|
||||
}
|
||||
|
||||
export function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
|
||||
function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
|
||||
const currentSkill = calculateSkill(exp, mult);
|
||||
const nextSkill = currentSkill + 1;
|
||||
|
||||
|
|
@ -60,7 +67,7 @@ export function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
|
|||
};
|
||||
}
|
||||
|
||||
export interface ISkillProgress {
|
||||
interface ISkillProgress {
|
||||
currentSkill: number;
|
||||
nextSkill: number;
|
||||
baseExperience: number;
|
||||
|
|
@ -71,7 +78,7 @@ export interface ISkillProgress {
|
|||
progress: number;
|
||||
}
|
||||
|
||||
export function getEmptySkillProgress(): ISkillProgress {
|
||||
function getEmptySkillProgress(): ISkillProgress {
|
||||
return {
|
||||
currentSkill: 0,
|
||||
nextSkill: 0,
|
||||
12
src/test.ts
12
src/test.ts
|
|
@ -1,9 +1,11 @@
|
|||
import { NS } from "@ns";
|
||||
import { scan } from "./utils/scan";
|
||||
import { startall } from "./utils/startall";
|
||||
import { kill } from "./utils/kill";
|
||||
import { ezgame } from "./ezgame";
|
||||
|
||||
export const main = (ns: NS) => {
|
||||
ns.tprint(ns.getPurchasedServerCost(256));
|
||||
console.log(ns.getPlayer());
|
||||
const server = ns.getServer("n00dles");
|
||||
const player = ns.getPlayer();
|
||||
const testResult = ezgame.formulas.hacking.growTime(server, player);
|
||||
const actualResult = ns.formulas.hacking.growTime(server, player);
|
||||
console.log(testResult);
|
||||
console.log(actualResult);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
// format the date/time
|
||||
// if the date is today, show the time
|
||||
/**
|
||||
* Format the date/time.
|
||||
* If the date is today, show the time. Otherwise, show the date in "day month year" format.
|
||||
* @param dateString The date string to format
|
||||
* @returns Formatted date/time string
|
||||
*/
|
||||
export const utilityFormatDate = (dateString: string): string => {
|
||||
const date = new Date(dateString);
|
||||
const today = new Date();
|
||||
|
|
@ -20,7 +24,11 @@ export const utilityFormatDate = (dateString: string): string => {
|
|||
}
|
||||
};
|
||||
|
||||
// format the file sizes
|
||||
/**
|
||||
* Format bytes into human-readable size
|
||||
* @param bytes Number of bytes to format
|
||||
* @returns Formatted size string
|
||||
*/
|
||||
export const utilityFormatSize = (bytes: number): string => {
|
||||
if (bytes === 0) return "0 Bytes";
|
||||
|
||||
|
|
@ -32,7 +40,11 @@ export const utilityFormatSize = (bytes: number): string => {
|
|||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
||||
};
|
||||
|
||||
// UNformat the file sizes
|
||||
/**
|
||||
* Convert a formatted size string back to bytes
|
||||
* @param formattedSize Formatted size string (must be in the same format produced by `utilityFormatSize()`)
|
||||
* @returns Number of bytes
|
||||
*/
|
||||
export const utilityUnformatSize = (formattedSize: string): number => {
|
||||
const sizes = ["Bytes", "KB", "MB", "GB"];
|
||||
const [value, unit] = formattedSize.split(" ");
|
||||
|
|
@ -40,9 +52,12 @@ export const utilityUnformatSize = (formattedSize: string): number => {
|
|||
return parseFloat(value) * Math.pow(1024, index);
|
||||
};
|
||||
|
||||
// extract filename and extension from a path
|
||||
// heeheeheehaw safe coding my boys 🤠
|
||||
// only consider things after the last period
|
||||
/**
|
||||
* Extract filename stem and extension from a file path
|
||||
* @param filePath The file path to parse
|
||||
* @returns Object containing `fileStem` and `fileExtension`. `fileStem` is the filename without the extension, and `fileExtension` is the extension in lowercase (or an empty string if there is no extension).
|
||||
* @throws Error if the file path is invalid
|
||||
*/
|
||||
export const utilityExtractFilename = (filePath: string): { fileStem: string; fileExtension: string } | null => {
|
||||
const lastSlashIndex = filePath.lastIndexOf("/");
|
||||
const lastDotIndex = filePath.lastIndexOf(".");
|
||||
|
|
@ -74,11 +89,11 @@ export const utilityExtractFilename = (filePath: string): { fileStem: string; fi
|
|||
};
|
||||
|
||||
/**
|
||||
* Clamps the value on a lower and an upper bound
|
||||
* @param {number} value Value to clamp
|
||||
* @param {number} min Lower bound, defaults to negative Number.MAX_VALUE
|
||||
* @param {number} max Upper bound, defaults to Number.MAX_VALUE
|
||||
* @returns {number} Clamped value
|
||||
* Clamps a value to a lower and upper bound
|
||||
* @param value Value to clamp
|
||||
* @param min Lower bound, defaults to negative `Number.MAX_VALUE`
|
||||
* @param max Upper bound, defaults to `Number.MAX_VALUE`
|
||||
* @returns Clamped value
|
||||
*/
|
||||
export function clampNumber(value: number, min: number = -Number.MAX_VALUE, max: number = Number.MAX_VALUE): number {
|
||||
if (isNaN(value)) {
|
||||
|
|
@ -89,11 +104,11 @@ export function clampNumber(value: number, min: number = -Number.MAX_VALUE, max:
|
|||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to an integer within a lower and an upper bound
|
||||
* @param {number} value Value to clamp
|
||||
* @param {number} min Lower bound, defaults to negative Number.MAX_SAFE_INTEGER
|
||||
* @param {number} max Upper bound, defaults to Number.MAX_SAFE_INTEGER
|
||||
* @returns {number} Clamped integer value
|
||||
* Clamps a value to an integer within a lower and upper bound
|
||||
* @param value Value to clamp
|
||||
* @param min Lower bound, defaults to negative `Number.MAX_SAFE_INTEGER`
|
||||
* @param max Upper bound, defaults to `Number.MAX_SAFE_INTEGER`
|
||||
* @returns Clamped integer value
|
||||
*/
|
||||
export function clampInteger(
|
||||
value: number,
|
||||
|
|
@ -108,11 +123,32 @@ export function clampInteger(
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks that a variable is a valid number. A valid number
|
||||
* must be a "number" type and cannot be NaN
|
||||
* @param {number} n The number to check
|
||||
* @returns {boolean} True if n is a valid number, false otherwise
|
||||
* Checks that a variable is a valid number
|
||||
* A valid number must be of type "number" and cannot be NaN
|
||||
* @param n The number to check
|
||||
* @returns True if n is a valid number, false otherwise
|
||||
*/
|
||||
export function isValidNumber(n: number): boolean {
|
||||
return typeof n === "number" && !isNaN(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number between min and max (inclusive)
|
||||
* @param min Minimum value (inclusive)
|
||||
* @param max Maximum value (inclusive)
|
||||
* @returns Random number between min and max
|
||||
*/
|
||||
export function randomNumber(min: number, max: number): number {
|
||||
if (min > max) throw new Error("min cannot be greater than max");
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random integer between min and max (inclusive)
|
||||
* @param min Minimum value (inclusive)
|
||||
* @param max Maximum value (inclusive)
|
||||
* @returns Random integer between min and max
|
||||
*/
|
||||
export function randomInteger(min: number, max: number): number {
|
||||
return Math.floor(randomNumber(min, max + 1));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue