Advertisement
Guest User

Untitled

a guest
Jun 23rd, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.84 KB | None | 0 0
  1. function optimize(params: any) {
  2. let {he_left, zone, fluffy, perks, weight, mod} = params;
  3. let {
  4. Looting_II, Carpentry_II, Motivation_II, Power_II, Toughness_II,
  5. Capable, Cunning, Curious,
  6. Overkill, Resourceful, Coordinated, Siphonology, Anticipation,
  7. Resilience, Meditation, Relentlessness, Carpentry, Artisanistry,
  8. Range, Agility, Bait, Trumps, Pheromones,
  9. Packrat, Motivation, Power, Toughness, Looting
  10. } = perks;
  11.  
  12. for (let name in perks)
  13. if ((<any> name).endsWith('_II'))
  14. perks[name].pack = pow(10, max(0, floor(log(he_left) / log(100) - 4.2)));
  15.  
  16. for (let name of ['whip', 'magn', 'taunt', 'ven'])
  17. mod[name] = pow(1.003, zone * 99 * 0.03 * mod[name]);
  18.  
  19. const books = pow(1.25, zone) * pow(zone > 100 ? 1.28 : 1.2, max(zone - 59, 0));
  20. const gigas = max(0, min(zone - 60, zone/2 - 25, zone/3 - 12, zone/5, zone/10 + 17, 39));
  21. const base_housing = pow(1.25, 5 + min(zone / 2, 30) + gigas);
  22. const mystic = zone >= 25 ? floor(min(zone / 5, 9 + zone / 25, 15)) : 0;
  23. const tacular = (20 + zone - zone % 5) / 100;
  24. const base_income = 600 * mod.whip * books;
  25. const base_helium = pow(zone - 19, 2);
  26. const max_tiers = zone / 5 + +((zone - 1) % 10 < 5);
  27. const exponents = {
  28. cost: pow(1.069, 0.85 * (zone < 60 ? 57 : 53)),
  29. attack: pow(1.19, 13),
  30. health: pow(1.19, 14),
  31. block: pow(1.19, 10),
  32. };
  33. const equip_cost = {
  34. attack: 211 * (weight.attack + weight.health) / weight.attack,
  35. health: 248 * (weight.attack + weight.health) / weight.health,
  36. block: 5 * (weight.attack + weight.health) / weight.health,
  37. };
  38.  
  39. // Number of ticks it takes to one-shot an enemy.
  40. function ticks() {
  41. return 1 + +(Agility.bonus > 0.9) + ceil(10 * Agility.bonus);
  42. }
  43.  
  44. function moti() {
  45. return Motivation.bonus * Motivation_II.bonus * Meditation.bonus;
  46. }
  47.  
  48. const looting = () => Looting.bonus * Looting_II.bonus;
  49.  
  50. function gem_income() {
  51. let drag = moti() * mod.whip;
  52. let loot = looting() * mod.magn * 0.75 * 0.8;
  53. let chronojest = mod.chronojest * drag * loot / 30;
  54. return drag + loot + chronojest;
  55. }
  56.  
  57. // Max population
  58. const trimps = mod.tent_city ? () => {
  59. let carp = Carpentry.bonus * Carpentry_II.bonus;
  60. let territory = Trumps.bonus;
  61. return 10 * (mod.taunt + territory * (mod.taunt - 1) * 111) * carp;
  62. } : () => {
  63. let carp = Carpentry.bonus * Carpentry_II.bonus;
  64. let bonus = 3 + log(gem_income() / Resourceful.bonus) / log(1.4);
  65. let territory = Trumps.bonus * zone;
  66. return 10 * (base_housing * bonus + territory) * carp * mod.taunt + mod.dg * carp;
  67. };
  68.  
  69. function income(ignore_prod?: boolean) {
  70. let storage = mod.storage * Resourceful.bonus / Packrat.bonus;
  71. let loot = looting() * mod.magn / ticks();
  72. let prod = ignore_prod ? 0 : moti() * mod.prod;
  73. let chronojest = mod.chronojest * 0.1 * prod * loot;
  74. return base_income * (prod + loot * mod.loot + chronojest) * (1 - storage) * trimps();
  75. }
  76.  
  77. function equip(stat: "attack" | "health" | "block") {
  78. let cost = equip_cost[stat] * Artisanistry.bonus;
  79. let levels = 1.136;
  80. let tiers = log(1 + income() / cost) / log(exponents.cost);
  81.  
  82. if (tiers > max_tiers + 0.45) {
  83. levels = log(1 + pow(exponents.cost, tiers - max_tiers) * 0.2) / log(1.2);
  84. tiers = max_tiers;
  85. }
  86. return levels * pow(exponents[stat], tiers);
  87. }
  88.  
  89. // Number of buildings of a given kind that can be built with the current income.
  90. // cost: base cost of the buildings
  91. // exp: cost increase for each new level of the building
  92. function building(cost: number, exp: number) {
  93. cost *= 4 * Resourceful.bonus;
  94. return log(1 + income(true) * (exp - 1) / cost) / log(exp);
  95. }
  96.  
  97. // Number of zones spent in the Magma
  98. function magma() {
  99. return max(zone - 229, 0);
  100. }
  101.  
  102. // function mancers() {
  103. // let tributes = building(10000, 1.05);
  104. // let mancers = log(loot * pow(1.05, tributes) / 1e62) / log(1.01);
  105. // return magma() ? 1 + 0.6 * (1 - pow(0.9999, mancers)) : 1;
  106. // }
  107. // Breed speed
  108. function breed() {
  109. let nurseries = building(2e6, 1.06) / (1 + 0.1 * min(magma(), 20));
  110. let potency = 0.0085 * (zone >= 60 ? 0.1 : 1) * pow(1.1, floor(zone / 5));
  111. return potency * pow(1.01, nurseries) * Pheromones.bonus * mod.ven;
  112. }
  113.  
  114. // Number of Trimps sent at a time, pre-gators
  115. let group_size: number[] = [];
  116.  
  117. for (let coord = 0; coord <= log(1 + he_left / 500e3) / log(1.3); ++coord) {
  118. let ratio = 1 + 0.25 * pow(0.98, coord);
  119. let available_coords = zone - 1 + (magma() ? 100 : 0);
  120. let result = 1;
  121. for (let i = 0; i < available_coords; ++i)
  122. result = ceil(result * ratio);
  123. group_size[coord] = result;
  124. }
  125.  
  126. // Strength multiplier from coordinations
  127. function soldiers() {
  128. let ratio = 1 + 0.25 * Coordinated.bonus;
  129. let pop = (mod.soldiers || trimps()) / 3;
  130. if (mod.soldiers > 1)
  131. pop += 36000 * Bait.bonus;
  132. let unbought_coords = max(0, log(group_size[Coordinated.level] / pop) / log(ratio));
  133. return group_size[0] * pow(1.25, -unbought_coords);
  134. }
  135.  
  136. // Fracional number of Amalgamators expected
  137. function gators() {
  138. if ((game && game.global.version < 4.8) || zone < 230 || mod.soldiers > 1 || jobless)
  139. return 0;
  140.  
  141. let ooms = log(trimps() / group_size[Coordinated.level]) / log(10);
  142. return max(0, (ooms - 7 + floor((zone - 215) / 100)) / 3);
  143. }
  144.  
  145. // Total attack
  146. function attack() {
  147. let attack = (0.15 + equip('attack')) * pow(0.8, magma());
  148. attack *= Power.bonus * Power_II.bonus * Relentlessness.bonus;
  149. attack *= Siphonology.bonus * Range.bonus * Anticipation.bonus;
  150. attack *= fluffy.attack[Capable.level];
  151. attack *= 1 + 0.5 * gators();
  152. return soldiers() * attack;
  153. }
  154.  
  155. // Total survivability (accounts for health and block)
  156. function health() {
  157. let health = (0.6 + equip('health')) * pow(0.8, magma());
  158. health *= Toughness.bonus * Toughness_II.bonus * Resilience.bonus;
  159.  
  160. // block
  161. let gyms = building(400, 1.185);
  162. let trainers = jobless ? 0 : (gyms * log(1.185) - log(1 + gyms)) / log(1.1) + 25 - mystic;
  163. let block = 0.04 * gyms * pow(1 + mystic / 100, gyms) * (1 + tacular * trainers);
  164.  
  165. // target number of attacks to survive
  166. let attacks = 60;
  167.  
  168. if (zone < 70 || jobless) { // no geneticists
  169. // number of ticks needed to repopulate an army
  170. let timer = log(1 + soldiers() * breed() / Bait.bonus) / log(1 + breed());
  171. attacks = timer / ticks();
  172. }
  173.  
  174. else { // geneticists
  175. let fighting = min(group_size[Coordinated.level] / trimps(), 1 / 3);
  176. let target_speed = fighting > 1e-9 ?
  177. (pow(0.5 / (0.5 - fighting), 0.1 / mod.breed_timer) - 1) * 10 :
  178. fighting / mod.breed_timer;
  179. let geneticists = log(breed() / target_speed) / -log(0.98);
  180. health *= pow(1.01, geneticists);
  181. health *= pow(1.332, gators());
  182. }
  183.  
  184. health /= attacks;
  185. if (zone < 60)
  186. block += equip('block');
  187. else
  188. block = min(block, 4 * health);
  189.  
  190. return soldiers() * (block + health);
  191. }
  192.  
  193. const xp = () => Cunning.bonus * Curious.bonus;
  194. const agility = () => 1 / Agility.bonus;
  195. const helium = () => base_helium * looting() + 45;
  196. const overkill = () => Overkill.bonus;
  197.  
  198. const stats: {[key: string]: () => number} = { agility, helium, xp, attack, health, overkill, trimps, income };
  199.  
  200. function score() {
  201. let result = 0;
  202. for (let i in weight) {
  203. if (!weight[i])
  204. continue;
  205. let stat = stats[i]();
  206. if (!isFinite(stat))
  207. throw Error(i + ' is ' + stat);
  208. result += weight[i] * log(stat);
  209. }
  210.  
  211. return result;
  212. }
  213.  
  214. function recompute_marginal_efficiencies() {
  215. let baseline = score();
  216.  
  217. for (let name in perks) {
  218. let perk = perks[name];
  219. if (perk.cost_increment || !perk.levellable(he_left))
  220. continue;
  221. perk.level_up(1);
  222. perk.gain = score() - baseline;
  223. perk.level_up(-1);
  224. }
  225.  
  226. for (let name of ['Looting', 'Carpentry', 'Motivation', 'Power', 'Toughness'])
  227. perks[name + '_II'].gain = perks[name].gain * perks[name + '_II'].log_ratio() / perks[name].log_ratio();
  228. }
  229.  
  230. function solve_quadratic_equation(a: number, b: number, c: number): number {
  231. let delta = b * b - 4 * a * c;
  232. return (-b + sqrt(delta)) / (2 * a);
  233. }
  234.  
  235. function spend_he(perk: Perk, budget: number) {
  236. perk.gain /= perk.log_ratio();
  237.  
  238. if (perk.cost_increment) {
  239. let ratio = (1 + perk.level) / (1 + Looting_II.level + Carpentry_II.level + Motivation_II.level + Power_II.level + Toughness_II.level);
  240. budget *= 0.5 * ratio ** 2;
  241. let x = solve_quadratic_equation(perk.cost_increment / 2, perk.cost - perk.cost_increment / 2, -budget);
  242. he_left -= perk.level_up(floor(max(min(x, perk.max_level - perk.level), 1, perk.level / 1e12)));
  243. }
  244. else {
  245. budget **= 0.5;
  246. do he_left -= perk.level_up(1);
  247. while (perk.cost < budget && perk.level < perk.max_level)
  248. }
  249.  
  250. perk.gain *= perk.log_ratio();
  251. }
  252.  
  253. mod.loot *= 20.8; // TODO: check that this is correct
  254. weight.agility = (weight.helium + weight.attack) / 2;
  255. weight.overkill = 0.25 * weight.attack * (2 - pow(0.9, weight.helium / weight.attack));
  256.  
  257. if (zone > 90 && mod.soldiers <= 1 && Bait.min_level == 0)
  258. Bait.max_level = 0;
  259.  
  260. // Fluffy
  261. fluffy.attack = [];
  262. let potential = log(0.003 * fluffy.xp / pow(5, fluffy.prestige) + 1) / log(4);
  263. for (let cap = 0; cap <= 10; ++cap) {
  264. let level = min(floor(potential), cap);
  265. let progress = level == cap ? 0 : (pow(4, potential - level) - 1) / 3;
  266. fluffy.attack[cap] = 1 + pow(5, fluffy.prestige) * 0.1 * (level / 2 + progress) * (level + 1);
  267. }
  268.  
  269. // Minimum levels on perks
  270. for (let name in perks) {
  271. let perk = perks[name];
  272. if (perk.cost_increment)
  273. he_left -= perk.level_up(perk.min_level);
  274. else while (perk.level < perk.min_level)
  275. he_left -= perk.level_up(1);
  276. }
  277.  
  278. if (zone > 300 && weight.xp > 0) {
  279. let ratio = 0.25;
  280. while (Capable.levellable(he_left * ratio)) {
  281. he_left -= Capable.level_up(1);
  282. ratio = Capable.level <= floor(potential) ? 0.25 : 0.01;
  283. }
  284. }
  285.  
  286. if (zone <= 300 || potential >= Capable.level)
  287. weight.xp = 0;
  288.  
  289. if (he_left < 0)
  290. throw (game && game.global.canRespecPerks) ?
  291. "You don’t have enough Helium to afford your Fixed Perks." :
  292. "You don’t have a respec available.";
  293.  
  294. // Main loop
  295. let sorted_perks: Perk[] = Object.keys(perks).map(name => perks[name]).filter(perk => perk.levellable(he_left));
  296.  
  297. for (let x = 0.999; x > 1e-12; x *= x) {
  298. let he_target = he_left * x;
  299. recompute_marginal_efficiencies();
  300. sorted_perks.sort((a, b) => b.gain / b.cost - a.gain / a.cost);
  301.  
  302. while (he_left > he_target && sorted_perks.length) {
  303. let best = sorted_perks.shift()!;
  304. if (!best.levellable(he_left))
  305. continue;
  306.  
  307. spend_he(best, he_left - he_target);
  308.  
  309. // sorted_perks.splice(sorted_perks.findIndex(p => p.gain / p.cost > best.gain / best.cost), 0, best);
  310. let i = 0;
  311. while (sorted_perks[i] && sorted_perks[i].gain / sorted_perks[i].cost > best.gain / best.cost)
  312. i++;
  313. sorted_perks.splice(i, 0, best);
  314. }
  315. }
  316.  
  317. if (he_left < Toughness_II.cost / 256 && Toughness_II.level > 0)
  318. --Toughness_II.level;
  319.  
  320. return [he_left, perks];
  321. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement