Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function optimize(params: any) {
- let {he_left, zone, fluffy, perks, weight, mod} = params;
- let {
- Looting_II, Carpentry_II, Motivation_II, Power_II, Toughness_II,
- Capable, Cunning, Curious,
- Overkill, Resourceful, Coordinated, Siphonology, Anticipation,
- Resilience, Meditation, Relentlessness, Carpentry, Artisanistry,
- Range, Agility, Bait, Trumps, Pheromones,
- Packrat, Motivation, Power, Toughness, Looting
- } = perks;
- for (let name in perks)
- if ((<any> name).endsWith('_II'))
- perks[name].pack = pow(10, max(0, floor(log(he_left) / log(100) - 4.2)));
- for (let name of ['whip', 'magn', 'taunt', 'ven'])
- mod[name] = pow(1.003, zone * 99 * 0.03 * mod[name]);
- const books = pow(1.25, zone) * pow(zone > 100 ? 1.28 : 1.2, max(zone - 59, 0));
- const gigas = max(0, min(zone - 60, zone/2 - 25, zone/3 - 12, zone/5, zone/10 + 17, 39));
- const base_housing = pow(1.25, 5 + min(zone / 2, 30) + gigas);
- const mystic = zone >= 25 ? floor(min(zone / 5, 9 + zone / 25, 15)) : 0;
- const tacular = (20 + zone - zone % 5) / 100;
- const base_income = 600 * mod.whip * books;
- const base_helium = pow(zone - 19, 2);
- const max_tiers = zone / 5 + +((zone - 1) % 10 < 5);
- const exponents = {
- cost: pow(1.069, 0.85 * (zone < 60 ? 57 : 53)),
- attack: pow(1.19, 13),
- health: pow(1.19, 14),
- block: pow(1.19, 10),
- };
- const equip_cost = {
- attack: 211 * (weight.attack + weight.health) / weight.attack,
- health: 248 * (weight.attack + weight.health) / weight.health,
- block: 5 * (weight.attack + weight.health) / weight.health,
- };
- // Number of ticks it takes to one-shot an enemy.
- function ticks() {
- return 1 + +(Agility.bonus > 0.9) + ceil(10 * Agility.bonus);
- }
- function moti() {
- return Motivation.bonus * Motivation_II.bonus * Meditation.bonus;
- }
- const looting = () => Looting.bonus * Looting_II.bonus;
- function gem_income() {
- let drag = moti() * mod.whip;
- let loot = looting() * mod.magn * 0.75 * 0.8;
- let chronojest = mod.chronojest * drag * loot / 30;
- return drag + loot + chronojest;
- }
- // Max population
- const trimps = mod.tent_city ? () => {
- let carp = Carpentry.bonus * Carpentry_II.bonus;
- let territory = Trumps.bonus;
- return 10 * (mod.taunt + territory * (mod.taunt - 1) * 111) * carp;
- } : () => {
- let carp = Carpentry.bonus * Carpentry_II.bonus;
- let bonus = 3 + log(gem_income() / Resourceful.bonus) / log(1.4);
- let territory = Trumps.bonus * zone;
- return 10 * (base_housing * bonus + territory) * carp * mod.taunt + mod.dg * carp;
- };
- function income(ignore_prod?: boolean) {
- let storage = mod.storage * Resourceful.bonus / Packrat.bonus;
- let loot = looting() * mod.magn / ticks();
- let prod = ignore_prod ? 0 : moti() * mod.prod;
- let chronojest = mod.chronojest * 0.1 * prod * loot;
- return base_income * (prod + loot * mod.loot + chronojest) * (1 - storage) * trimps();
- }
- function equip(stat: "attack" | "health" | "block") {
- let cost = equip_cost[stat] * Artisanistry.bonus;
- let levels = 1.136;
- let tiers = log(1 + income() / cost) / log(exponents.cost);
- if (tiers > max_tiers + 0.45) {
- levels = log(1 + pow(exponents.cost, tiers - max_tiers) * 0.2) / log(1.2);
- tiers = max_tiers;
- }
- return levels * pow(exponents[stat], tiers);
- }
- // Number of buildings of a given kind that can be built with the current income.
- // cost: base cost of the buildings
- // exp: cost increase for each new level of the building
- function building(cost: number, exp: number) {
- cost *= 4 * Resourceful.bonus;
- return log(1 + income(true) * (exp - 1) / cost) / log(exp);
- }
- // Number of zones spent in the Magma
- function magma() {
- return max(zone - 229, 0);
- }
- // function mancers() {
- // let tributes = building(10000, 1.05);
- // let mancers = log(loot * pow(1.05, tributes) / 1e62) / log(1.01);
- // return magma() ? 1 + 0.6 * (1 - pow(0.9999, mancers)) : 1;
- // }
- // Breed speed
- function breed() {
- let nurseries = building(2e6, 1.06) / (1 + 0.1 * min(magma(), 20));
- let potency = 0.0085 * (zone >= 60 ? 0.1 : 1) * pow(1.1, floor(zone / 5));
- return potency * pow(1.01, nurseries) * Pheromones.bonus * mod.ven;
- }
- // Number of Trimps sent at a time, pre-gators
- let group_size: number[] = [];
- for (let coord = 0; coord <= log(1 + he_left / 500e3) / log(1.3); ++coord) {
- let ratio = 1 + 0.25 * pow(0.98, coord);
- let available_coords = zone - 1 + (magma() ? 100 : 0);
- let result = 1;
- for (let i = 0; i < available_coords; ++i)
- result = ceil(result * ratio);
- group_size[coord] = result;
- }
- // Strength multiplier from coordinations
- function soldiers() {
- let ratio = 1 + 0.25 * Coordinated.bonus;
- let pop = (mod.soldiers || trimps()) / 3;
- if (mod.soldiers > 1)
- pop += 36000 * Bait.bonus;
- let unbought_coords = max(0, log(group_size[Coordinated.level] / pop) / log(ratio));
- return group_size[0] * pow(1.25, -unbought_coords);
- }
- // Fracional number of Amalgamators expected
- function gators() {
- if ((game && game.global.version < 4.8) || zone < 230 || mod.soldiers > 1 || jobless)
- return 0;
- let ooms = log(trimps() / group_size[Coordinated.level]) / log(10);
- return max(0, (ooms - 7 + floor((zone - 215) / 100)) / 3);
- }
- // Total attack
- function attack() {
- let attack = (0.15 + equip('attack')) * pow(0.8, magma());
- attack *= Power.bonus * Power_II.bonus * Relentlessness.bonus;
- attack *= Siphonology.bonus * Range.bonus * Anticipation.bonus;
- attack *= fluffy.attack[Capable.level];
- attack *= 1 + 0.5 * gators();
- return soldiers() * attack;
- }
- // Total survivability (accounts for health and block)
- function health() {
- let health = (0.6 + equip('health')) * pow(0.8, magma());
- health *= Toughness.bonus * Toughness_II.bonus * Resilience.bonus;
- // block
- let gyms = building(400, 1.185);
- let trainers = jobless ? 0 : (gyms * log(1.185) - log(1 + gyms)) / log(1.1) + 25 - mystic;
- let block = 0.04 * gyms * pow(1 + mystic / 100, gyms) * (1 + tacular * trainers);
- // target number of attacks to survive
- let attacks = 60;
- if (zone < 70 || jobless) { // no geneticists
- // number of ticks needed to repopulate an army
- let timer = log(1 + soldiers() * breed() / Bait.bonus) / log(1 + breed());
- attacks = timer / ticks();
- }
- else { // geneticists
- let fighting = min(group_size[Coordinated.level] / trimps(), 1 / 3);
- let target_speed = fighting > 1e-9 ?
- (pow(0.5 / (0.5 - fighting), 0.1 / mod.breed_timer) - 1) * 10 :
- fighting / mod.breed_timer;
- let geneticists = log(breed() / target_speed) / -log(0.98);
- health *= pow(1.01, geneticists);
- health *= pow(1.332, gators());
- }
- health /= attacks;
- if (zone < 60)
- block += equip('block');
- else
- block = min(block, 4 * health);
- return soldiers() * (block + health);
- }
- const xp = () => Cunning.bonus * Curious.bonus;
- const agility = () => 1 / Agility.bonus;
- const helium = () => base_helium * looting() + 45;
- const overkill = () => Overkill.bonus;
- const stats: {[key: string]: () => number} = { agility, helium, xp, attack, health, overkill, trimps, income };
- function score() {
- let result = 0;
- for (let i in weight) {
- if (!weight[i])
- continue;
- let stat = stats[i]();
- if (!isFinite(stat))
- throw Error(i + ' is ' + stat);
- result += weight[i] * log(stat);
- }
- return result;
- }
- function recompute_marginal_efficiencies() {
- let baseline = score();
- for (let name in perks) {
- let perk = perks[name];
- if (perk.cost_increment || !perk.levellable(he_left))
- continue;
- perk.level_up(1);
- perk.gain = score() - baseline;
- perk.level_up(-1);
- }
- for (let name of ['Looting', 'Carpentry', 'Motivation', 'Power', 'Toughness'])
- perks[name + '_II'].gain = perks[name].gain * perks[name + '_II'].log_ratio() / perks[name].log_ratio();
- }
- function solve_quadratic_equation(a: number, b: number, c: number): number {
- let delta = b * b - 4 * a * c;
- return (-b + sqrt(delta)) / (2 * a);
- }
- function spend_he(perk: Perk, budget: number) {
- perk.gain /= perk.log_ratio();
- if (perk.cost_increment) {
- let ratio = (1 + perk.level) / (1 + Looting_II.level + Carpentry_II.level + Motivation_II.level + Power_II.level + Toughness_II.level);
- budget *= 0.5 * ratio ** 2;
- let x = solve_quadratic_equation(perk.cost_increment / 2, perk.cost - perk.cost_increment / 2, -budget);
- he_left -= perk.level_up(floor(max(min(x, perk.max_level - perk.level), 1, perk.level / 1e12)));
- }
- else {
- budget **= 0.5;
- do he_left -= perk.level_up(1);
- while (perk.cost < budget && perk.level < perk.max_level)
- }
- perk.gain *= perk.log_ratio();
- }
- mod.loot *= 20.8; // TODO: check that this is correct
- weight.agility = (weight.helium + weight.attack) / 2;
- weight.overkill = 0.25 * weight.attack * (2 - pow(0.9, weight.helium / weight.attack));
- if (zone > 90 && mod.soldiers <= 1 && Bait.min_level == 0)
- Bait.max_level = 0;
- // Fluffy
- fluffy.attack = [];
- let potential = log(0.003 * fluffy.xp / pow(5, fluffy.prestige) + 1) / log(4);
- for (let cap = 0; cap <= 10; ++cap) {
- let level = min(floor(potential), cap);
- let progress = level == cap ? 0 : (pow(4, potential - level) - 1) / 3;
- fluffy.attack[cap] = 1 + pow(5, fluffy.prestige) * 0.1 * (level / 2 + progress) * (level + 1);
- }
- // Minimum levels on perks
- for (let name in perks) {
- let perk = perks[name];
- if (perk.cost_increment)
- he_left -= perk.level_up(perk.min_level);
- else while (perk.level < perk.min_level)
- he_left -= perk.level_up(1);
- }
- if (zone > 300 && weight.xp > 0) {
- let ratio = 0.25;
- while (Capable.levellable(he_left * ratio)) {
- he_left -= Capable.level_up(1);
- ratio = Capable.level <= floor(potential) ? 0.25 : 0.01;
- }
- }
- if (zone <= 300 || potential >= Capable.level)
- weight.xp = 0;
- if (he_left < 0)
- throw (game && game.global.canRespecPerks) ?
- "You don’t have enough Helium to afford your Fixed Perks." :
- "You don’t have a respec available.";
- // Main loop
- let sorted_perks: Perk[] = Object.keys(perks).map(name => perks[name]).filter(perk => perk.levellable(he_left));
- for (let x = 0.999; x > 1e-12; x *= x) {
- let he_target = he_left * x;
- recompute_marginal_efficiencies();
- sorted_perks.sort((a, b) => b.gain / b.cost - a.gain / a.cost);
- while (he_left > he_target && sorted_perks.length) {
- let best = sorted_perks.shift()!;
- if (!best.levellable(he_left))
- continue;
- spend_he(best, he_left - he_target);
- // sorted_perks.splice(sorted_perks.findIndex(p => p.gain / p.cost > best.gain / best.cost), 0, best);
- let i = 0;
- while (sorted_perks[i] && sorted_perks[i].gain / sorted_perks[i].cost > best.gain / best.cost)
- i++;
- sorted_perks.splice(i, 0, best);
- }
- }
- if (he_left < Toughness_II.cost / 256 && Toughness_II.level > 0)
- --Toughness_II.level;
- return [he_left, perks];
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement