Created
December 27, 2021 19:11
-
-
Save oatmealine/42fd7849ebcb17e3479e8c5a65f1a212 to your computer and use it in GitHub Desktop.
Formulas.exe but in plain JS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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