Skip to content

Instantly share code, notes, and snippets.

@oatmealine
Created December 27, 2021 19:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oatmealine/42fd7849ebcb17e3479e8c5a65f1a212 to your computer and use it in GitHub Desktop.
Save oatmealine/42fd7849ebcb17e3479e8c5a65f1a212 to your computer and use it in GitHub Desktop.
Formulas.exe but in plain JS
// skills
function calculateSkill(exp, mult = 1) {
return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1);
}
function calculateExp(skill, mult = 1) {
return Math.exp((skill / mult + 200) / 32) - 534.6;
}
// hacking
function hackChance(server, player) {
const hackFactor = 1.75;
const difficultyMult = (100 - server.hackDifficulty) / 100;
const skillMult = hackFactor * player.hacking;
const skillChance = (skillMult - server.requiredHackingSkill) / skillMult;
const chance =
skillChance * difficultyMult * player.hacking_chance_mult * calculateIntelligenceBonus(player.intelligence, 1);
if (chance > 1) {
return 1;
}
if (chance < 0) {
return 0;
}
return chance;
}
function hackExp(server, player) {
const baseExpGain = 3;
const diffFactor = 0.3;
if (server.baseDifficulty == null) {
server.baseDifficulty = server.hackDifficulty;
}
let expGain = baseExpGain;
expGain += server.baseDifficulty * player.hacking_exp_mult * diffFactor;
return expGain * BitNodeMultipliers.HackExpGain;
}
function hackPercent(server, player) {
const balanceFactor = 240;
const difficultyMult = (100 - server.hackDifficulty) / 100;
const skillMult = (player.hacking - (server.requiredHackingSkill - 1)) / player.hacking;
const percentMoneyHacked = (difficultyMult * skillMult * player.hacking_money_mult) / balanceFactor;
if (percentMoneyHacked < 0) {
return 0;
}
if (percentMoneyHacked > 1) {
return 1;
}
return percentMoneyHacked * BitNodeMultipliers.ScriptHackMoney;
}
function growPercent(server, threads, p, cores = 1) {
const numServerGrowthCycles = Math.max(Math.floor(threads), 0);
//Get adjusted growth rate, which accounts for server security
const growthRate = /*CONSTANTS.ServerBaseGrowthRate*/ 1.03;
let adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
if (adjGrowthRate > /*CONSTANTS.ServerMaxGrowthRate*/ 1.0035) {
adjGrowthRate = /*CONSTANTS.ServerMaxGrowthRate*/ 1.0035;
}
//Calculate adjusted server growth rate based on parameters
const serverGrowthPercentage = server.serverGrowth / 100;
const numServerGrowthCyclesAdjusted =
numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
//Apply serverGrowth for the calculated number of growth cycles
const coreBonus = 1 + (cores - 1) / 16;
return Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * p.hacking_grow_mult * coreBonus);
}
function hackTime(server, player) {
const difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
const baseDiff = 500;
const baseSkill = 50;
const diffFactor = 2.5;
let skillFactor = diffFactor * difficultyMult + baseDiff;
// tslint:disable-next-line
skillFactor /= player.hacking + baseSkill;
const hackTimeMultiplier = 5;
const hackingTime =
(hackTimeMultiplier * skillFactor) /
(player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1));
return hackingTime * 1000;
}
function growTime(server, player) {
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
return growTimeMultiplier * hackTime(server, player) * 1000;
}
function weakenTime(server, player) {
const weakenTimeMultiplier = 4; // Relative to hacking time
return weakenTimeMultiplier * hackTime(server, player) * 1000;
}
// hacknetNodes
const constants = = {
MoneyGainPerLevel: 1.5,
BaseCost: 1000,
LevelBaseCost: 1,
RamBaseCost: 30e3,
CoreBaseCost: 500e3,
PurchaseNextMult: 1.85,
UpgradeLevelMult: 1.04,
UpgradeRamMult: 1.28,
UpgradeCoreMult: 1.48,
MaxLevel: 200,
MaxRam: 64,
MaxCores: 16,
};
function moneyGainRate(level, ram, cores, mult) {
const gainPerLevel = constants.MoneyGainPerLevel;
const levelMult = level * gainPerLevel;
const ramMult = Math.pow(1.035, ram - 1);
const coresMult = (cores + 5) / 6;
return levelMult * ramMult * coresMult * mult * BitNodeMultipliers.HacknetNodeMoney;
}
function levelUpgradeCost(startingLevel, extraLevels = 1, costMult = 1) {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingLevel >= constants.MaxLevel) {
return Infinity;
}
const mult = constants.UpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = startingLevel;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier += constants.LevelBaseCost * Math.pow(mult, currLevel);
++currLevel;
}
return (constants.BaseCost / 2) * totalMultiplier * costMult;
}
function ramUpgradeCost(startingRam, extraLevels = 1, costMult = 1) {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingRam >= constants.MaxRam) {
return Infinity;
}
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(startingRam));
let currentRam = startingRam;
for (let i = 0; i < sanitizedLevels; ++i) {
const baseCost = currentRam * constants.RamBaseCost;
const mult = Math.pow(constants.UpgradeRamMult, numUpgrades);
totalCost += baseCost * mult;
currentRam *= 2;
++numUpgrades;
}
totalCost *= costMult;
return totalCost;
}
function coreUpgradeCost(startingCore, extraLevels = 1, costMult = 1) {
const sanitizedCores = Math.round(extraLevels);
if (isNaN(sanitizedCores) || sanitizedCores < 1) {
return 0;
}
if (startingCore >= constants.MaxCores) {
return Infinity;
}
const coreBaseCost = constants.CoreBaseCost;
const mult = constants.UpgradeCoreMult;
let totalCost = 0;
let currentCores = startingCore;
for (let i = 0; i < sanitizedCores; ++i) {
totalCost += coreBaseCost * Math.pow(mult, currentCores - 1);
++currentCores;
}
totalCost *= costMult;
return totalCost;
}
function hacknetNodeCost(n, mult = 1) {
if (n <= 0) {
return 0;
}
return constants.BaseCost * Math.pow(constants.PurchaseNextMult, n - 1) * mult;
}
// hacknetServers
const constants = {
HashesPerLevel: 0.001,
BaseCost: 50e3,
RamBaseCost: 200e3,
CoreBaseCost: 1e6,
CacheBaseCost: 10e6,
PurchaseMult: 3.2,
UpgradeLevelMult: 1.1,
UpgradeRamMult: 1.4,
UpgradeCoreMult: 1.55,
UpgradeCacheMult: 1.85,
MaxServers: 20,
MaxLevel: 300,
MaxRam: 8192,
MaxCores: 128,
MaxCache: 15,
};
function hashGainRate(
level,
ramUsed,
maxRam,
cores,
mult,
) {
const baseGain = constants.HashesPerLevel * level;
const ramMultiplier = Math.pow(1.07, Math.log2(maxRam));
const coreMultiplier = 1 + (cores - 1) / 5;
const ramRatio = 1 - ramUsed / maxRam;
return baseGain * ramMultiplier * coreMultiplier * ramRatio * mult * BitNodeMultipliers.HacknetNodeMoney;
}
function levelUpgradeCost(startingLevel, extraLevels = 1, costMult = 1) {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingLevel >= constants.MaxLevel) {
return Infinity;
}
const mult = constants.UpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = startingLevel;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier += Math.pow(mult, currLevel);
++currLevel;
}
return 10 * constants.BaseCost * totalMultiplier * costMult;
}
function ramUpgradeCost(startingRam, extraLevels = 1, costMult = 1) {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingRam >= constants.MaxRam) {
return Infinity;
}
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(startingRam));
let currentRam = startingRam;
for (let i = 0; i < sanitizedLevels; ++i) {
const baseCost = currentRam * constants.RamBaseCost;
const mult = Math.pow(constants.UpgradeRamMult, numUpgrades);
totalCost += baseCost * mult;
currentRam *= 2;
++numUpgrades;
}
totalCost *= costMult;
return totalCost;
}
function coreUpgradeCost(startingCores, extraLevels = 1, costMult = 1) {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingCores >= constants.MaxCores) {
return Infinity;
}
const mult = constants.UpgradeCoreMult;
let totalCost = 0;
let currentCores = startingCores;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += Math.pow(mult, currentCores - 1);
++currentCores;
}
totalCost *= constants.CoreBaseCost;
totalCost *= costMult;
return totalCost;
}
function cacheUpgradeCost(startingCache, extraLevels = 1) {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingCache >= constants.MaxCache) {
return Infinity;
}
const mult = constants.UpgradeCacheMult;
let totalCost = 0;
let currentCache = startingCache;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += Math.pow(mult, currentCache - 1);
++currentCache;
}
totalCost *= constants.CacheBaseCost;
return totalCost;
}
const HashUpgradesMetadata = [
{
cost: 4,
name: "Sell for Money",
value: 1e6,
},
{
costPerLevel: 100,
name: "Sell for Corporation Funds",
value: 1e9,
},
{
costPerLevel: 50,
name: "Reduce Minimum Security",
value: 0.98,
},
{
costPerLevel: 50,
name: "Increase Maximum Money",
value: 1.02,
},
{
costPerLevel: 50,
name: "Improve Studying",
value: 20, // Improves studying by value%
},
{
costPerLevel: 50,
name: "Improve Gym Training",
value: 20, // Improves training by value%
},
{
costPerLevel: 200,
name: "Exchange for Corporation Research",
value: 1000,
},
{
costPerLevel: 250,
name: "Exchange for Bladeburner Rank",
value: 100,
},
{
costPerLevel: 250,
name: "Exchange for Bladeburner SP",
value: 10,
},
{
costPerLevel: 200,
name: "Generate Coding Contract",
value: 1,
},
];
function getCost(name, levels) {
let upgrade = HashUpgradesMetadata.find(l => l.name === name);
if (!name) throw new Error(`Invalid Hash Upgrade: ${name}`);
if (typeof upgrade.cost === "number") {
return this.cost;
}
return Math.round((levels + 1) * upgrade.costPerLevel);
}
function hacknetServerCost(n, mult = 1) {
if (n - 1 >= constants.MaxServers) {
return Infinity;
}
return constants.BaseCost * Math.pow(constants.PurchaseMult, n - 1) * mult;
}
// gang
function wantedPenalty(gang) {
return gang.respect / (gang.respect + gang.wantedLevel);
}
function respectGain(gang, member, task) {
if (task.baseRespect === 0) return 0;
let statWeight =
(task.hackWeight / 100) * member.hack +
(task.strWeight / 100) * member.str +
(task.defWeight / 100) * member.def +
(task.dexWeight / 100) * member.dex +
(task.agiWeight / 100) * member.agi +
(task.chaWeight / 100) * member.cha;
statWeight -= 4 * task.difficulty;
if (statWeight <= 0) return 0;
const territoryMult = Math.max(0.005, Math.pow(gang.territory * 100, task.territory.respect) / 100);
const territoryPenalty = (0.2 * gang.territory + 0.8) * BitNodeMultipliers.GangSoftcap;
if (isNaN(territoryMult) || territoryMult <= 0) return 0;
const respectMult = calculateWantedPenalty(gang);
return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);
}
function wantedLevelGain(gang, member, task) {
if (task.baseWanted === 0) return 0;
let statWeight =
(task.hackWeight / 100) * member.hack +
(task.strWeight / 100) * member.str +
(task.defWeight / 100) * member.def +
(task.dexWeight / 100) * member.dex +
(task.agiWeight / 100) * member.agi +
(task.chaWeight / 100) * member.cha;
statWeight -= 3.5 * task.difficulty;
if (statWeight <= 0) return 0;
const territoryMult = Math.max(0.005, Math.pow(gang.territory * 100, task.territory.wanted) / 100);
if (isNaN(territoryMult) || territoryMult <= 0) return 0;
if (task.baseWanted < 0) {
return 0.4 * task.baseWanted * statWeight * territoryMult;
}
const calc = (7 * task.baseWanted) / Math.pow(3 * statWeight * territoryMult, 0.8);
// Put an arbitrary cap on this to prevent wanted level from rising too fast if the
// denominator is very small. Might want to rethink formula later
return Math.min(100, calc);
}
function moneyGain(gang, member, task) {
if (task.baseMoney === 0) return 0;
let statWeight =
(task.hackWeight / 100) * member.hack +
(task.strWeight / 100) * member.str +
(task.defWeight / 100) * member.def +
(task.dexWeight / 100) * member.dex +
(task.agiWeight / 100) * member.agi +
(task.chaWeight / 100) * member.cha;
statWeight -= 3.2 * task.difficulty;
if (statWeight <= 0) return 0;
const territoryMult = Math.max(0.005, Math.pow(gang.territory * 100, task.territory.money) / 100);
if (isNaN(territoryMult) || territoryMult <= 0) return 0;
const respectMult = calculateWantedPenalty(gang);
const territoryPenalty = (0.2 * gang.territory + 0.8) * BitNodeMultipliers.GangSoftcap;
return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);
}
function ascensionPointsGain(exp) {
return Math.max(exp - 1000, 0);
}
function ascensionMultiplier(points) {
return Math.max(Math.pow(points / 2000, 0.5), 1);
}
// misc - not included anywhere but needed for some calculations
function calculateIntelligenceBonus(intelligence, weight = 1) {
return 1 + (weight * Math.pow(intelligence, 0.8)) / 600;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment