TheresMoreHelp

Helper for TheresMoreGame

当前为 2022-12-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name TheresMoreHelp
  3. // @namespace TheresMoreGame.com
  4. // @match https://www.theresmoregame.com/play/
  5. // @grant none
  6. // @version 1.22.1
  7. // @description Helper for TheresMoreGame
  8. // @license MIT
  9. // @run-at document-idle
  10. // ==/UserScript==
  11.  
  12. ;(async () => {
  13. let cheatsOff = true
  14.  
  15. let scriptPaused = true
  16. let manualGold = false
  17. let haveManualResourceButtons = true
  18. let playingMarket = false
  19.  
  20. const buildingsList = [
  21. { name: 'City of Lights', alwaysBuild: true, isSafe: true },
  22. { name: 'Harbor district', alwaysBuild: true, isSafe: true },
  23. { name: 'Stock exchange', alwaysBuild: true, isSafe: true },
  24. { name: 'Mana pit', alwaysBuild: true, isSafe: true },
  25. { name: 'Great bombard', alwaysBuild: true, isSafe: true },
  26. { name: 'Refugees district', alwaysBuild: true, isSafe: true },
  27. { name: 'Academy of Freethinkers', alwaysBuild: true, isSafe: true },
  28. { name: 'City center', alwaysBuild: true, isSafe: true },
  29. { name: 'Cathedral', alwaysBuild: true, isSafe: true },
  30. { name: 'Great fair', alwaysBuild: true, isSafe: true },
  31. { name: 'Palisade', alwaysBuild: true, isSafe: true },
  32. { name: 'Wall', alwaysBuild: true, isSafe: true },
  33. { name: 'City of Lights part', alwaysBuild: true, isSafe: true },
  34. { name: 'Harbor district part', alwaysBuild: true, isSafe: true },
  35. { name: 'Stock exchange part', alwaysBuild: true, isSafe: true },
  36. { name: 'Mana pit part', alwaysBuild: true, isSafe: true },
  37. { name: 'Great bombard part', alwaysBuild: true, isSafe: true },
  38. { name: 'Refugees district part', alwaysBuild: true, isSafe: true },
  39. { name: 'A. of Freethinkers Part', alwaysBuild: true, isSafe: true },
  40. { name: 'City center part', alwaysBuild: true, isSafe: true },
  41. { name: 'Great fair unit', alwaysBuild: true, isSafe: true },
  42. { name: 'Cathedral part', alwaysBuild: true, isSafe: true },
  43. { name: 'Guild of craftsmen', alwaysBuild: true, isSafe: true },
  44. { name: 'Machines of gods', alwaysBuild: true, isSafe: true },
  45. { name: 'Library of Theresmore', alwaysBuild: true, isSafe: true },
  46. { name: 'Monastery', alwaysBuild: true, isSafe: true },
  47. { name: 'Watchman Outpost', alwaysBuild: true, isSafe: true },
  48. { name: 'Hall of the dead', alwaysBuild: true, isSafe: true },
  49. { name: 'Sawmill', alwaysBuild: true, isSafe: true },
  50. { name: 'Monument', alwaysBuild: true, isSafe: true },
  51. { name: 'Foundry', alwaysBuild: true, isSafe: true },
  52. { name: 'Builder district', alwaysBuild: true, isSafe: true },
  53. { name: 'Gan Eden', alwaysBuild: true, isSafe: true },
  54. { name: 'Portal of the dead', alwaysBuild: true, isSafe: true },
  55. { name: 'Observatory', isSafe: true },
  56. { name: 'The Vaults', isSafe: true },
  57. { name: 'Credit union', isSafe: true },
  58. { name: 'Canava trading post', isSafe: true },
  59. { name: 'Bank', isSafe: true },
  60. { name: 'Marketplace', isSafe: true },
  61. { name: 'Artisan Workshop', isSafe: true },
  62. { name: 'Granary', isSafe: true },
  63. { name: 'School', isSafe: true },
  64. { name: 'University', isSafe: true },
  65. { name: 'Research plant', isSafe: true },
  66. { name: 'Undead Herds', isSafe: true },
  67. { name: 'Guarded warehouse', isSafe: true },
  68. { name: 'Fiefdom', isSafe: true },
  69. { name: 'Natronite refinery', isSafe: true },
  70. { name: 'Alchemical laboratory', isSafe: true },
  71. { name: 'Lumberjack Camp', isSafe: true },
  72. { name: 'Quarry', isSafe: true },
  73. { name: 'Mine', isSafe: true },
  74. { name: 'Palisade part', isSafe: true },
  75. { name: 'Wall part', isSafe: true },
  76. { name: 'Farm', isSafe: true },
  77. { name: 'Matter transmuter', isSafe: true },
  78. { name: 'Stable', isSafe: true },
  79. { name: 'Spiritual garden', isSafe: true },
  80. { name: 'Conclave', isSafe: true },
  81. { name: 'Magical tower', isSafe: true },
  82. { name: 'Temple', isSafe: true },
  83. { name: 'Altar of sacrifices', isSafe: true },
  84. { name: 'Fountain of Prosperity', isSafe: true },
  85. { name: 'Valley of plenty', isSafe: true },
  86. { name: 'Tax revenue checkpoints', isSafe: true },
  87. { name: 'Industrial plant', isSafe: true },
  88. { name: 'Magic Circle', isSafe: true },
  89. { name: 'Carpenter workshop', isSafe: true },
  90. { name: 'Grocery', isSafe: true },
  91. { name: 'Steelworks', isSafe: true },
  92. { name: 'Military academy', isSafe: true },
  93. { name: 'Ancient vault', isSafe: true },
  94. { name: 'Recruit training center', isSafe: true },
  95. { name: 'Officer training ground', isSafe: true },
  96. { name: 'Mansion', isSafe: false, requires: { resource: 'Food', parameter: 'speed', minValue: 3 } },
  97. { name: 'City Hall', isSafe: false, requires: { resource: 'Food', parameter: 'speed', minValue: 1.5 } },
  98. { name: 'Residential block', isSafe: false, requires: { resource: 'Food', parameter: 'speed', minValue: 5 } },
  99. { name: 'Common House', isSafe: false, requires: { resource: 'Food', parameter: 'speed', minValue: 1 } },
  100. { name: 'Storage facility', isSafe: true },
  101. { name: 'Ballista', isSafe: true },
  102. { name: 'Large warehouse', isSafe: true },
  103. { name: 'Large storehouse', isSafe: true },
  104. { name: 'Store', isSafe: true },
  105. { name: 'Natronite depot', isSafe: true },
  106. { name: 'Barracks', isSafe: true },
  107. { name: 'Minefield', isSafe: true },
  108. { name: 'Natronite balloon', isSafe: true },
  109. { name: 'Decryption of the portal', isSafe: true },
  110. { name: 'Fortune grove', isSafe: true },
  111. { name: 'Pillars of mana', isSafe: false, requires: { resource: 'Gold', parameter: 'speed', minValue: 100 } },
  112. ].filter((building) => building.name)
  113.  
  114. const lang = {
  115. pop_artisan: 'Artisan',
  116. pop_breeder: 'Breeder',
  117. pop_farmer: 'Farmer',
  118. pop_lumberjack: 'Lumberjack',
  119. pop_merchant: 'Merchant',
  120. pop_trader: 'Trader',
  121. pop_miner: 'Miner',
  122. pop_quarryman: 'Quarryman',
  123. pop_priest: 'Priest',
  124. pop_carpenter: 'Carpenter',
  125. pop_steelworker: 'Steelworker',
  126. pop_professor: 'Professor',
  127. pop_skymancer: 'Skymancer',
  128. pop_supplier: 'Supplier',
  129. pop_alchemist: 'Alchemist',
  130. pop_unemployed: 'Unemployed',
  131. pop_natro_refiner: 'Nat-Refiner',
  132. pop_researcher: 'Researcher',
  133. res_army: 'Army',
  134. res_coin: 'Coin',
  135. res_copper: 'Copper',
  136. res_cow: 'Cow',
  137. res_crystal: 'Crystal',
  138. res_faith: 'Faith',
  139. res_fame: 'Fame',
  140. res_food: 'Food',
  141. res_gold: 'Gold',
  142. res_horse: 'Horse',
  143. res_iron: 'Iron',
  144. res_legacy: 'Legacy',
  145. res_luck: 'Luck',
  146. res_mana: 'Mana',
  147. res_natronite: 'Natronite',
  148. res_population: 'Population',
  149. res_stone: 'Stone',
  150. res_relic: 'Relic',
  151. res_research: 'Research',
  152. res_tools: 'Tools',
  153. res_wood: 'Wood',
  154. res_building_material: 'Materials',
  155. res_steel: 'Steel',
  156. res_supplies: 'Supplies',
  157. res_saltpetre: 'Saltpetre',
  158. res_tome_wisdom: 'Tome of Wisdom',
  159. res_gem: 'Gem',
  160. }
  161.  
  162. const allJobs = [
  163. {
  164. id: 'unemployed',
  165. },
  166. {
  167. id: 'farmer',
  168. req: [
  169. {
  170. type: 'building',
  171. id: 'farm',
  172. value: 1,
  173. },
  174. ],
  175. gen: [
  176. {
  177. type: 'resource',
  178. id: 'food',
  179. value: 1.6,
  180. },
  181. ],
  182. },
  183. {
  184. id: 'lumberjack',
  185. req: [
  186. {
  187. type: 'building',
  188. id: 'lumberjack_camp',
  189. value: 1,
  190. },
  191. ],
  192. gen: [
  193. {
  194. type: 'resource',
  195. id: 'wood',
  196. value: 0.7,
  197. },
  198. ],
  199. },
  200. {
  201. id: 'quarryman',
  202. req: [
  203. {
  204. type: 'building',
  205. id: 'quarry',
  206. value: 1,
  207. },
  208. ],
  209. gen: [
  210. {
  211. type: 'resource',
  212. id: 'stone',
  213. value: 0.6,
  214. },
  215. ],
  216. },
  217. {
  218. id: 'miner',
  219. req: [
  220. {
  221. type: 'building',
  222. id: 'mine',
  223. value: 1,
  224. },
  225. ],
  226. gen: [
  227. {
  228. type: 'resource',
  229. id: 'copper',
  230. value: 0.5,
  231. },
  232. {
  233. type: 'resource',
  234. id: 'iron',
  235. value: 0.3,
  236. },
  237. ],
  238. },
  239. {
  240. id: 'artisan',
  241. req: [
  242. {
  243. type: 'building',
  244. id: 'artisan_workshop',
  245. value: 1,
  246. },
  247. ],
  248. gen: [
  249. {
  250. type: 'resource',
  251. id: 'gold',
  252. value: 0.5,
  253. },
  254. {
  255. type: 'resource',
  256. id: 'tools',
  257. value: 0.3,
  258. },
  259. ],
  260. },
  261. {
  262. id: 'merchant',
  263. req: [
  264. {
  265. type: 'building',
  266. id: 'marketplace',
  267. value: 1,
  268. },
  269. ],
  270. gen: [
  271. {
  272. type: 'resource',
  273. id: 'gold',
  274. value: 3,
  275. },
  276. ],
  277. },
  278. {
  279. id: 'trader',
  280. req: [
  281. {
  282. type: 'building',
  283. id: 'credit_union',
  284. value: 1,
  285. },
  286. ],
  287. gen: [
  288. {
  289. type: 'resource',
  290. id: 'gold',
  291. value: 6,
  292. },
  293. ],
  294. },
  295. {
  296. id: 'breeder',
  297. req: [
  298. {
  299. type: 'building',
  300. id: 'stable',
  301. value: 1,
  302. },
  303. ],
  304. gen: [
  305. {
  306. type: 'resource',
  307. id: 'cow',
  308. value: 0.2,
  309. },
  310. {
  311. type: 'resource',
  312. id: 'horse',
  313. value: 0.1,
  314. },
  315. ],
  316. },
  317. {
  318. id: 'carpenter',
  319. req: [
  320. {
  321. type: 'building',
  322. id: 'carpenter_workshop',
  323. value: 1,
  324. },
  325. ],
  326. gen: [
  327. {
  328. type: 'resource',
  329. id: 'building_material',
  330. value: 0.3,
  331. },
  332. {
  333. type: 'resource',
  334. id: 'wood',
  335. value: -3,
  336. },
  337. {
  338. type: 'resource',
  339. id: 'stone',
  340. value: -1.5,
  341. },
  342. {
  343. type: 'resource',
  344. id: 'tools',
  345. value: -0.5,
  346. },
  347. ],
  348. },
  349. {
  350. id: 'steelworker',
  351. req: [
  352. {
  353. type: 'building',
  354. id: 'steelworks',
  355. value: 1,
  356. },
  357. ],
  358. gen: [
  359. {
  360. type: 'resource',
  361. id: 'steel',
  362. value: 0.4,
  363. },
  364. {
  365. type: 'resource',
  366. id: 'copper',
  367. value: -1,
  368. },
  369. {
  370. type: 'resource',
  371. id: 'iron',
  372. value: -0.5,
  373. },
  374. ],
  375. },
  376. {
  377. id: 'professor',
  378. req: [
  379. {
  380. type: 'building',
  381. id: 'university',
  382. value: 1,
  383. },
  384. ],
  385. gen: [
  386. {
  387. type: 'resource',
  388. id: 'crystal',
  389. value: 0.06,
  390. },
  391. {
  392. type: 'resource',
  393. id: 'research',
  394. value: 1,
  395. },
  396. ],
  397. },
  398. {
  399. id: 'researcher',
  400. req: [
  401. {
  402. type: 'building',
  403. id: 'research_plant',
  404. value: 1,
  405. },
  406. ],
  407. gen: [
  408. {
  409. type: 'resource',
  410. id: 'research',
  411. value: 3,
  412. },
  413. ],
  414. },
  415. {
  416. id: 'supplier',
  417. req: [
  418. {
  419. type: 'building',
  420. id: 'grocery',
  421. value: 1,
  422. },
  423. ],
  424. gen: [
  425. {
  426. type: 'resource',
  427. id: 'supplies',
  428. value: 0.4,
  429. },
  430. {
  431. type: 'resource',
  432. id: 'food',
  433. value: -2,
  434. },
  435. {
  436. type: 'resource',
  437. id: 'cow',
  438. value: -0.2,
  439. },
  440. ],
  441. },
  442. {
  443. id: 'skymancer',
  444. req: [
  445. {
  446. type: 'building',
  447. id: 'observatory',
  448. value: 1,
  449. },
  450. ],
  451. gen: [
  452. {
  453. type: 'resource',
  454. id: 'faith',
  455. value: 3,
  456. },
  457. {
  458. type: 'resource',
  459. id: 'mana',
  460. value: 3,
  461. },
  462. ],
  463. },
  464. {
  465. id: 'alchemist',
  466. req: [
  467. {
  468. type: 'building',
  469. id: 'alchemic_laboratory',
  470. value: 1,
  471. },
  472. ],
  473. gen: [
  474. {
  475. type: 'resource',
  476. id: 'saltpetre',
  477. value: 0.7,
  478. },
  479. ],
  480. },
  481. {
  482. id: 'natro_refiner',
  483. req: [
  484. {
  485. type: 'building',
  486. id: 'natronite_refinery',
  487. value: 1,
  488. },
  489. ],
  490. gen: [
  491. {
  492. type: 'resource',
  493. id: 'natronite',
  494. value: 1,
  495. },
  496. {
  497. type: 'resource',
  498. id: 'mana',
  499. value: -5,
  500. },
  501. {
  502. type: 'resource',
  503. id: 'saltpetre',
  504. value: -0.5,
  505. },
  506. ],
  507. },
  508. ]
  509. .filter((job) => job.gen && job.gen.length)
  510. .map((job) => {
  511. return {
  512. id: lang[`pop_${job.id}`],
  513. gen: job.gen
  514. .filter((gen) => gen.type === 'resource')
  515. .map((gen) => {
  516. return {
  517. id: lang[`res_${gen.id}`],
  518. value: gen.value,
  519. }
  520. }),
  521. }
  522. })
  523. .map((job) => {
  524. return {
  525. id: job.id,
  526. isSafe: !job.gen.find((gen) => gen.value < 0),
  527. resourcesGenerated: job.gen
  528. .filter((gen) => gen.value > 0)
  529. .map((gen) => {
  530. return { id: gen.id, value: gen.value }
  531. }),
  532. resourcesUsed: job.gen
  533. .filter((gen) => gen.value < 0)
  534. .map((gen) => {
  535. return { id: gen.id, value: gen.value }
  536. }),
  537. }
  538. })
  539.  
  540. const modes = {
  541. RESEARCH: 'Research',
  542. GAIN_GOLD: 'Gain Gold',
  543. BUILD: 'Build',
  544. BUY_BATTLE_ANGEL: 'Buy BA',
  545. ASSIGN_POPULATION: 'Assign Population',
  546. DEFAULT: 'Default',
  547. }
  548. let mode = modes.DEFAULT
  549. let marketPlaceAvailable = false
  550.  
  551. const pages = {
  552. BUILD: 'Build',
  553. RESEARCH: 'Research',
  554. POPULATION: 'Population',
  555. ARMY: 'Army',
  556. MARKETPLACE: 'Marketplace',
  557. MAGIC: 'Magic',
  558. UNKNOWN: 'Unknown',
  559. }
  560.  
  561. const resourcesToTrade = ['Cow', 'Horse', 'Food', 'Copper', 'Wood', 'Stone', 'Iron', 'Tools']
  562. const timeToWaitUntilFullGold = 60
  563.  
  564. let takePageActionTimeout
  565.  
  566. const sleep = (miliseconds) => new Promise((resolve) => setTimeout(resolve, miliseconds))
  567.  
  568. // https://stackoverflow.com/a/55366435
  569. class NumberParser {
  570. constructor(locale) {
  571. const format = new Intl.NumberFormat(locale)
  572. const parts = format.formatToParts(12345.6)
  573. const numerals = Array.from({ length: 10 }).map((_, i) => format.format(i))
  574. const index = new Map(numerals.map((d, i) => [d, i]))
  575. this._group = new RegExp(`[${parts.find((d) => d.type === 'group').value}]`, 'g')
  576. this._decimal = new RegExp(`[${parts.find((d) => d.type === 'decimal').value}]`)
  577. this._numeral = new RegExp(`[${numerals.join('')}]`, 'g')
  578. this._index = (d) => index.get(d)
  579. }
  580.  
  581. parse(string) {
  582. let multiplier = 1
  583. if (string.includes('K')) {
  584. multiplier = 1000
  585. } else if (string.includes('M')) {
  586. multiplier = 1000000
  587. }
  588.  
  589. return (string = string.replace('K', '').replace('M', '').trim().replace(this._group, '').replace(this._decimal, '.').replace(this._numeral, this._index))
  590. ? +string * multiplier
  591. : NaN
  592. }
  593. }
  594. const numberParser = new NumberParser()
  595.  
  596. const formatTime = (timeToFormat) => {
  597. const timeValues = {
  598. seconds: 0,
  599. minutes: 0,
  600. hours: 0,
  601. days: 0,
  602. }
  603.  
  604. let timeShort = ''
  605. let timeLong = ''
  606.  
  607. timeValues.seconds = timeToFormat % 60
  608. timeToFormat = (timeToFormat - (timeToFormat % 60)) / 60
  609. timeValues.minutes = timeToFormat % 60
  610. timeToFormat = (timeToFormat - (timeToFormat % 60)) / 60
  611. timeValues.hours = timeToFormat % 24
  612. timeToFormat = (timeToFormat - (timeToFormat % 24)) / 24
  613. timeValues.days = timeToFormat
  614.  
  615. if (timeValues.days) {
  616. timeShort += `${timeValues.days}d `
  617. timeLong += `${timeValues.days} days `
  618. }
  619. if (timeValues.hours) {
  620. timeShort += `${timeValues.hours}h `
  621. timeLong += `${timeValues.hours} hrs `
  622. }
  623. if (timeValues.minutes) {
  624. timeShort += `${timeValues.minutes}m `
  625. timeLong += `${timeValues.minutes} min `
  626. }
  627. if (timeValues.seconds) {
  628. timeShort += `${timeValues.seconds}s `
  629. timeLong += `${timeValues.seconds} sec `
  630. }
  631.  
  632. timeShort = timeShort.trim()
  633. timeLong = timeLong.trim()
  634.  
  635. return {
  636. timeShort,
  637. timeLong,
  638. timeValues,
  639. }
  640. }
  641.  
  642. window.switchScriptState = () => {
  643. scriptPaused = !scriptPaused
  644. window.localStorage.setItem('TMH_cheatsOff', JSON.stringify(false))
  645. window.localStorage.setItem('TMH_scriptPaused', JSON.stringify(scriptPaused))
  646.  
  647. if (!scriptPaused) {
  648. setTimeout(() => {
  649. window.location.reload()
  650. }, 60 * 60 * 1000)
  651.  
  652. mode = modes.DEFAULT
  653. switchPage(pages.BUILD)
  654. }
  655. }
  656.  
  657. window.switchManualGold = () => {
  658. manualGold = !manualGold
  659. window.localStorage.setItem('TMH_cheatsOff', JSON.stringify(false))
  660. window.localStorage.setItem('TMH_manualGold', JSON.stringify(manualGold))
  661. }
  662.  
  663. const getAllButtons = () => {
  664. let buttonsList = []
  665. document.querySelectorAll('#maintabs-container > div > div[role=tabpanel] button.btn.btn-dark:not(.btn-off)').forEach((button) => buttonsList.push(button))
  666.  
  667. return buttonsList
  668. }
  669.  
  670. const getResource = (resourceName = 'Gold') => {
  671. let resourceFound = false
  672. let resourceToFind = { name: resourceName, current: 0, max: 0, speed: 0, ttf: null, ttz: null }
  673. const resources = document.querySelectorAll('#root div > div > div > table > tbody > tr > td:nth-child(1) > span')
  674. resources.forEach((resource) => {
  675. if (resource.textContent.includes(resourceName)) {
  676. resourceFound = true
  677. const values = resource.parentNode.parentNode.childNodes[1].textContent
  678. .split('/')
  679. .map((x) => numberParser.parse(x.replace(/[^0-9KM\-,\.]/g, '').trim()))
  680. resourceToFind.current = values[0]
  681. resourceToFind.max = values[1]
  682.  
  683. resourceToFind.speed = numberParser.parse(resource.parentNode.parentNode.childNodes[2].textContent.replace(/[^0-9KM\-,\.]/g, '').trim()) || 0
  684.  
  685. resourceToFind.ttf =
  686. resourceToFind.speed > 0 && resourceToFind.max !== resourceToFind.current
  687. ? formatTime(Math.ceil((resourceToFind.max - resourceToFind.current) / resourceToFind.speed))
  688. : null
  689. resourceToFind.ttz =
  690. resourceToFind.speed < 0 && resourceToFind.current ? formatTime(Math.ceil(resourceToFind.current / (resourceToFind.speed * -1))) : null
  691. }
  692. })
  693.  
  694. return resourceFound ? resourceToFind : null
  695. }
  696.  
  697. const getAllResources = () => {
  698. const resources = document.querySelectorAll('#root div > div > div > table > tbody > tr > td:nth-child(1) > span')
  699. const resourceNames = []
  700.  
  701. resources.forEach((resource) => resourceNames.push(resource.textContent.trim()))
  702.  
  703. return resourceNames
  704. }
  705.  
  706. const getPage = () => {
  707. let page = pages.UNKNOWN
  708.  
  709. const pageSelectedSelector = document.querySelector('#main-tabs > div > button[aria-selected="true"]')
  710.  
  711. if (pageSelectedSelector) {
  712. const pageSelected = pageSelectedSelector.textContent
  713.  
  714. if (pageSelected.includes('Build')) {
  715. page = pages.BUILD
  716. } else if (pageSelected.includes('Research')) {
  717. page = pages.RESEARCH
  718. } else if (pageSelected.includes('Population')) {
  719. page = pages.POPULATION
  720. } else if (pageSelected.includes('Army')) {
  721. page = pages.ARMY
  722. } else if (pageSelected.includes('Marketplace')) {
  723. page = pages.MARKETPLACE
  724. } else if (pageSelected.includes('Magic')) {
  725. page = pages.MAGIC
  726. }
  727. }
  728.  
  729. return page
  730. }
  731.  
  732. const hasPage = (page) => {
  733. let foundPage = false
  734.  
  735. const navButtons = document.querySelectorAll('#main-tabs > div > button')
  736. navButtons.forEach((button) => {
  737. if (button.innerText.includes(page)) {
  738. foundPage = true
  739. }
  740. })
  741.  
  742. return foundPage
  743. }
  744.  
  745. const switchPage = async (page) => {
  746. if (cheatsOff) return
  747. if (scriptPaused) return
  748.  
  749. let foundPage = hasPage(page)
  750. if (!foundPage) {
  751. mode = modes.DEFAULT
  752. switchPage(pages.BUILD)
  753. return
  754. }
  755.  
  756. let switchedPage = false
  757.  
  758. const navButtons = document.querySelectorAll('#main-tabs > div > button')
  759. navButtons.forEach((button) => {
  760. if (button.innerText.includes(page) && button.getAttribute('aria-selected') !== 'true') {
  761. button.click()
  762. switchedPage = true
  763. }
  764. })
  765.  
  766. if (switchedPage) {
  767. console.log(`$-> Switched page to ${page}`)
  768. await sleep(3500)
  769. }
  770.  
  771. clearTimeout(takePageActionTimeout)
  772. takePageActionTimeout = setTimeout(takePageAction, 1)
  773. }
  774.  
  775. const takePageAction = async () => {
  776. if (cheatsOff) return
  777. if (scriptPaused) return
  778.  
  779. let page = getPage()
  780.  
  781. if (page !== pages.BUILD && mode === modes.BUILD) {
  782. switchPage(pages.BUILD)
  783. return
  784. } else if (page !== pages.RESEARCH && mode === modes.RESEARCH) {
  785. switchPage(pages.RESEARCH)
  786. return
  787. } else if (page !== pages.MARKETPLACE && mode === modes.GAIN_GOLD) {
  788. switchPage(pages.MARKETPLACE)
  789. return
  790. } else if (page !== pages.ARMY && mode === modes.BUY_BATTLE_ANGEL) {
  791. switchPage(pages.ARMY)
  792. return
  793. } else if (page !== pages.POPULATION && mode === modes.ASSIGN_POPULATION) {
  794. switchPage(pages.POPULATION)
  795. return
  796. }
  797.  
  798. if (page === pages.BUILD) {
  799. setTimeout(spendResourcesBuilding, 1)
  800. } else if (page === pages.RESEARCH) {
  801. setTimeout(performReserach, 1)
  802. } else if (page === pages.MARKETPLACE) {
  803. setTimeout(playMarket, 1)
  804. } else if (page === pages.ARMY) {
  805. setTimeout(buyArmy, 1)
  806. } else if (page === pages.POPULATION) {
  807. setTimeout(assignPopulation, 1)
  808. } else {
  809. clearTimeout(takePageActionTimeout)
  810. takePageActionTimeout = setTimeout(takePageAction, 1000)
  811. }
  812. }
  813.  
  814. const hasUnassignedPopulation = () => {
  815. let unassignedPopulation = false
  816.  
  817. const navButtons = document.querySelectorAll('#main-tabs > div > button')
  818. navButtons.forEach((button) => {
  819. if (button.innerText.includes(pages.POPULATION)) {
  820. unassignedPopulation = !!button.querySelector('span')
  821. }
  822. })
  823.  
  824. return unassignedPopulation
  825. }
  826.  
  827. const spendResourcesBuilding = async () => {
  828. if (cheatsOff) return
  829. if (scriptPaused) return
  830.  
  831. if (getPage() !== pages.BUILD) {
  832. clearTimeout(takePageActionTimeout)
  833. takePageActionTimeout = setTimeout(takePageAction, 1000)
  834. return
  835. }
  836.  
  837. const buttonsList = getAllButtons()
  838. const buildingNames = []
  839.  
  840. buttonsList.forEach((button) => buildingNames.push(button.innerText.split('\n').shift()))
  841.  
  842. let hasBuilt = false
  843. let shouldBuild = false
  844.  
  845. if (buildingNames.length) {
  846. for (let i = 0; i < buildingsList.length && !hasBuilt; i++) {
  847. if (hasBuilt) break
  848.  
  849. const building = buildingsList[i]
  850.  
  851. shouldBuild = buildingNames.includes(building.name)
  852.  
  853. if (!building.isSafe) {
  854. const requiredResource = getResource(building.requires.resource)
  855. if (!requiredResource) {
  856. shouldBuild = false
  857. } else {
  858. shouldBuild = shouldBuild && requiredResource[building.requires.parameter] > building.requires.minValue
  859. }
  860. }
  861.  
  862. if (shouldBuild) {
  863. if (building.alwaysBuild || mode === modes.BUILD) {
  864. const buildButton = buttonsList.find((button) => button.innerText.includes(building.name))
  865.  
  866. if (buildButton) {
  867. buildButton.click()
  868. hasBuilt = true
  869. console.log(`#-> Started building ${building.name}`)
  870. await sleep(1000)
  871. }
  872.  
  873. mode = modes.DEFAULT
  874. break
  875. } else {
  876. mode = modes.BUILD
  877. break
  878. }
  879. }
  880. }
  881. }
  882.  
  883. await sleep(5000)
  884.  
  885. if (mode === modes.BUILD || shouldBuild || hasBuilt) {
  886. await switchPage(pages.BUILD)
  887. } else {
  888. const gold = getResource('Gold')
  889.  
  890. let shouldSell = resourcesToTrade.find((resName) => {
  891. const res = getResource(resName)
  892. if (res && (res.current === res.max || res.current + res.speed * timeToWaitUntilFullGold >= res.max)) return true
  893. })
  894.  
  895. if (hasPage(pages.POPULATION) && hasUnassignedPopulation()) {
  896. mode = modes.ASSIGN_POPULATION
  897. await switchPage(pages.POPULATION)
  898. } else if (hasPage(pages.ARMY) && canAffordBA() && shouldBuyBA()) {
  899. mode = modes.BUY_BATTLE_ANGEL
  900. await switchPage(pages.ARMY)
  901. } else if (marketPlaceAvailable && gold.current + gold.speed * timeToWaitUntilFullGold < gold.max && shouldSell) {
  902. mode = modes.GAIN_GOLD
  903. await switchPage(pages.MARKETPLACE)
  904. } else {
  905. mode = modes.RESEARCH
  906. await switchPage(pages.RESEARCH)
  907. }
  908. }
  909. }
  910.  
  911. const performReserach = async () => {
  912. if (cheatsOff) return
  913. if (scriptPaused) return
  914.  
  915. if (getPage() !== pages.RESEARCH) {
  916. clearTimeout(takePageActionTimeout)
  917. takePageActionTimeout = setTimeout(takePageAction, 1000)
  918. return
  919. }
  920.  
  921. const manualResearches = ['A moonlight night', 'Dragon assault', 'Mysterious robbery', 'The Fallen Angel reveal']
  922.  
  923. let didResearch = false
  924.  
  925. const buttonsList = getAllButtons()
  926. const researchesList = []
  927.  
  928. buttonsList.forEach(
  929. (button) => !manualResearches.includes(button.innerText.split('\n').shift()) && researchesList.push(button.innerText.split('\n').shift())
  930. )
  931.  
  932. if (researchesList.length) {
  933. while (!didResearch && researchesList.length) {
  934. const research = researchesList.shift()
  935.  
  936. buttonsList.forEach((button) => {
  937. if (button.innerText.split('\n').shift() === research) {
  938. button.click()
  939. didResearch = true
  940. console.log(`%-> Researching ${research}`)
  941. }
  942. })
  943. }
  944. }
  945.  
  946. if (didResearch) {
  947. await sleep(5000)
  948. } else {
  949. await sleep(2000)
  950. }
  951.  
  952. mode = modes.DEFAULT
  953. await switchPage(pages.BUILD)
  954. }
  955.  
  956. const playMarket = async () => {
  957. if (cheatsOff) return
  958. if (playingMarket) return
  959.  
  960. if (getPage() !== pages.MARKETPLACE) {
  961. clearTimeout(takePageActionTimeout)
  962. takePageActionTimeout = setTimeout(takePageAction, 1000)
  963. return
  964. }
  965.  
  966. let gold = getResource('Gold')
  967.  
  968. let shouldSell = resourcesToTrade.find((resName) => {
  969. const res = getResource(resName)
  970. if (res && res.current === res.max) return true
  971. })
  972.  
  973. if (gold && gold.current < gold.max && shouldSell) {
  974. playingMarket = true
  975.  
  976. const resourceHoldersQSA = document.querySelectorAll('div > div.tab-container > div > div > div')
  977. const resourceHolders = []
  978.  
  979. if (resourceHoldersQSA) {
  980. resourceHoldersQSA.forEach((resourceHolder) => {
  981. const resName = resourceHolder.querySelector('h5').innerText
  982. const res = getResource(resName)
  983.  
  984. if (resourcesToTrade.includes(resName) && res && (res.current === res.max || res.current + res.speed * timeToWaitUntilFullGold >= res.max)) {
  985. resourceHolders.push(resourceHolder)
  986. }
  987. })
  988. }
  989.  
  990. for (let i = 0; i < resourceHolders.length; i++) {
  991. gold = getResource('Gold')
  992. const resourceHolder = resourceHolders[i]
  993. const resName = resourceHolder.querySelector('h5').innerText
  994. let res = getResource(resName)
  995.  
  996. const initialPrice = numberParser.parse(resourceHolder.querySelector('div:nth-child(2) > div > table > tbody > tr > td:nth-child(2)').innerText)
  997. let price = initialPrice
  998. let sellButtons = resourceHolder.querySelectorAll('div:nth-child(2) > div.grid.gap-3 button:not(.btn-dark)')
  999.  
  1000. while (sellButtons && sellButtons.length && gold.current < gold.max && res.current + res.speed * timeToWaitUntilFullGold * 2 >= res.max) {
  1001. let maxSellButton = 2
  1002. const missingResToSell = Math.ceil((gold.max - gold.current) / price)
  1003.  
  1004. if (missingResToSell < 80) {
  1005. maxSellButton = 0
  1006. } else if (missingResToSell < 800) {
  1007. maxSellButton = 1
  1008. }
  1009. maxSellButton = Math.min(maxSellButton, sellButtons.length - 1)
  1010. sellButtons[maxSellButton].click()
  1011. console.log(`$$> Selling ${sellButtons[maxSellButton].innerText} of ${res.name} for ${price}`)
  1012. await sleep(10)
  1013. sellButtons = resourceHolder.querySelectorAll('div:nth-child(2) > div.grid.gap-3 button:not(.btn-dark)')
  1014. gold = getResource('Gold')
  1015. res = getResource(resName)
  1016. price = numberParser.parse(resourceHolder.querySelector('div:nth-child(2) > div > table > tbody > tr > td:nth-child(2)').innerText)
  1017. await sleep(1)
  1018.  
  1019. if (price / initialPrice < 0.1) {
  1020. break
  1021. }
  1022. }
  1023. }
  1024.  
  1025. playingMarket = false
  1026. }
  1027.  
  1028. mode = modes.RESEARCH
  1029. await switchPage(pages.RESEARCH)
  1030. }
  1031.  
  1032. const canAffordBA = () => {
  1033. const faith = getResource('Faith')
  1034. const mana = getResource('Mana')
  1035.  
  1036. if (faith && mana) {
  1037. if (faith.current >= 2000 && mana.current >= 600) {
  1038. return true
  1039. }
  1040. }
  1041.  
  1042. return false
  1043. }
  1044.  
  1045. const shouldBuyBA = () => {
  1046. const faith = getResource('Faith')
  1047. const mana = getResource('Mana')
  1048.  
  1049. if (faith && mana) {
  1050. if (
  1051. faith.current + faith.speed * timeToWaitUntilFullGold >= faith.max &&
  1052. mana.current + mana.speed * timeToWaitUntilFullGold >= mana.max &&
  1053. mana.speed > 10
  1054. ) {
  1055. return true
  1056. }
  1057. }
  1058.  
  1059. return false
  1060. }
  1061.  
  1062. const buyArmy = async () => {
  1063. if (cheatsOff) return
  1064. if (scriptPaused) return
  1065.  
  1066. if (getPage() !== pages.ARMY) {
  1067. clearTimeout(takePageActionTimeout)
  1068. takePageActionTimeout = setTimeout(takePageAction, 1000)
  1069. return
  1070. }
  1071.  
  1072. if (canAffordBA() && shouldBuyBA()) {
  1073. const allButtonsQSA = document.querySelectorAll('div > div > div > div > div > span > button:not(.btn-off)')
  1074. let buyBAButton = null
  1075.  
  1076. allButtonsQSA.forEach((button) => {
  1077. if (button.innerText.includes('Battle Angel')) {
  1078. buyBAButton = button
  1079. }
  1080. })
  1081.  
  1082. if (buyBAButton) {
  1083. buyBAButton.click()
  1084. console.log(`@-> Buying Battle Angel(s)`)
  1085. await sleep(5000)
  1086. }
  1087. }
  1088.  
  1089. mode = modes.RESEARCH
  1090. await switchPage(pages.RESEARCH)
  1091. }
  1092.  
  1093. const assignPopulation = async () => {
  1094. if (cheatsOff) return
  1095. if (scriptPaused) return
  1096.  
  1097. if (getPage() !== pages.POPULATION) {
  1098. clearTimeout(takePageActionTimeout)
  1099. takePageActionTimeout = setTimeout(takePageAction, 1000)
  1100. return
  1101. }
  1102.  
  1103. let canAssignJobs = true
  1104. const container = document.querySelector('#maintabs-container > div > div[role=tabpanel]')
  1105. let availablePop = container
  1106. .querySelector('div > span.ml-2')
  1107. .textContent.split('/')
  1108. .map((pop) => numberParser.parse(pop.trim()))
  1109.  
  1110. const availableJobsQSA = container.querySelectorAll('h5')
  1111. const availableJobs = []
  1112.  
  1113. availableJobsQSA.forEach((job) => {
  1114. const jobTitle = job.textContent.trim()
  1115. availableJobs.push({
  1116. ...allJobs.find((allJob) => allJob.id === jobTitle),
  1117. container: job.parentElement.parentElement,
  1118. })
  1119. })
  1120.  
  1121. if (availablePop[0] > 0) {
  1122. while (canAssignJobs) {
  1123. const jobsWithSpace = availableJobs.filter((job) => !!job.container.querySelector('button.btn-green'))
  1124. canAssignJobs = false
  1125.  
  1126. if (jobsWithSpace.length) {
  1127. if (getResource('Food').speed <= 0) {
  1128. const foodJob = jobsWithSpace.find((job) => job.resourcesGenerated.find((res) => res.id === 'Food'))
  1129. if (foodJob) {
  1130. const addJobButton = foodJob.container.querySelector('button.btn-green')
  1131. if (addJobButton) {
  1132. console.log(`**> Assigning worker as ${foodJob.id}`)
  1133.  
  1134. addJobButton.click()
  1135. canAssignJobs = true
  1136. await sleep(1000)
  1137. }
  1138. }
  1139. } else {
  1140. let unassigned = container
  1141. .querySelector('div > span.ml-2')
  1142. .textContent.split('/')
  1143. .map((pop) => numberParser.parse(pop.trim()))
  1144. .shift()
  1145.  
  1146. if (unassigned > 0) {
  1147. const resources = [
  1148. 'Natronite',
  1149. 'Saltpetre',
  1150. 'Tools',
  1151. 'Wood',
  1152. 'Stone',
  1153. 'Iron',
  1154. 'Copper',
  1155. 'Mana',
  1156. 'Faith',
  1157. 'Research',
  1158. 'Materials',
  1159. 'Steel',
  1160. 'Supplies',
  1161. 'Gold',
  1162. 'Crystal',
  1163. 'Horse',
  1164. 'Cow',
  1165. ]
  1166. .filter((res) => getResource(res))
  1167. .filter((res) => jobsWithSpace.find((job) => job.resourcesGenerated.find((resGen) => resGen.id === res)))
  1168.  
  1169. const resourcesWithNegativeGen = resources.filter((res) => getResource(res) && res.speed < 0)
  1170. const resourcesWithNoGen = resources.filter((res) => !resourcesWithNegativeGen.includes(res) && getResource(res) && !res.speed)
  1171. const resourcesLeft = resources.filter((res) => !resourcesWithNegativeGen.includes(res) && !resourcesWithNoGen.includes(res))
  1172.  
  1173. const resourcesSorted = resourcesWithNegativeGen.concat(resourcesWithNoGen).concat(resourcesLeft)
  1174.  
  1175. if (resourcesSorted.length) {
  1176. for (let i = 0; i < resourcesSorted.length; i++) {
  1177. if (unassigned === 0) break
  1178.  
  1179. const resourceName = resourcesSorted[i]
  1180.  
  1181. const jobsForResource = jobsWithSpace
  1182. .filter((job) => job.resourcesGenerated.find((resGen) => resGen.id === resourceName))
  1183. .sort(
  1184. (a, b) =>
  1185. b.resourcesGenerated.find((resGen) => resGen.id === resourceName).value -
  1186. a.resourcesGenerated.find((resGen) => resGen.id === resourceName).value
  1187. )
  1188.  
  1189. if (jobsForResource.length) {
  1190. for (let i = 0; i < jobsForResource.length; i++) {
  1191. if (unassigned === 0) break
  1192. const job = jobsForResource[i]
  1193.  
  1194. let isSafeToAdd = job.isSafe
  1195.  
  1196. if (!job.isSafe) {
  1197. job.resourcesUsed.forEach((resUsed) => {
  1198. const res = getResource(resUsed.id)
  1199.  
  1200. if (!res || res.speed < Math.abs(resUsed.value * 2)) {
  1201. isSafeToAdd = false
  1202. }
  1203. })
  1204. }
  1205.  
  1206. if (isSafeToAdd) {
  1207. const addJobButton = job.container.querySelector('button.btn-green')
  1208. if (addJobButton) {
  1209. console.log(`*-> Assigning worker as ${job.id}`)
  1210.  
  1211. addJobButton.click()
  1212. unassigned -= 1
  1213. canAssignJobs = !!unassigned
  1214. await sleep(1000)
  1215. }
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. }
  1222. }
  1223. }
  1224.  
  1225. const unassigned = container
  1226. .querySelector('div > span.ml-2')
  1227. .textContent.split('/')
  1228. .map((pop) => numberParser.parse(pop.trim()))
  1229. .shift()
  1230. if (unassigned === 0) {
  1231. canAssignJobs = false
  1232. }
  1233.  
  1234. await sleep(10)
  1235. }
  1236. }
  1237.  
  1238. mode = modes.RESEARCH
  1239. await switchPage(pages.RESEARCH)
  1240. }
  1241.  
  1242. const managePanel = async () => {
  1243. if (cheatsOff) return
  1244.  
  1245. const controlPanel = document.querySelector('div#theresMoreHelpControlPanel')
  1246.  
  1247. let scriptState = scriptPaused ? `▶️` : `⏸️`
  1248. let manualGoldState = manualGold ? '🤑' : `😅`
  1249.  
  1250. if (!controlPanel) {
  1251. const controlPanelElement = document.createElement('div')
  1252. controlPanelElement.id = 'theresMoreHelpControlPanel'
  1253. controlPanelElement.classList.add('dark')
  1254. controlPanelElement.classList.add('dark:bg-mydark-300')
  1255. controlPanelElement.style.position = 'fixed'
  1256. controlPanelElement.style.bottom = '10px'
  1257. controlPanelElement.style.left = '10px'
  1258. controlPanelElement.style.zIndex = '99999999'
  1259. controlPanelElement.style.border = '1px black solid'
  1260. controlPanelElement.style.padding = '10px'
  1261.  
  1262. controlPanelElement.innerHTML = `
  1263. <p class="mb-2">TheresMoreHelp:
  1264. <button onClick="window.switchScriptState()" title="Start/stop script" class="scriptState">${scriptState}</button>
  1265. <button onClick="window.switchManualGold()" title="Always play market" class="manualGold">${manualGoldState}</button>
  1266. </p>
  1267. <p class="currentPage text-xs mb-2 text-orange-500">Page: ${getPage()}</p>
  1268. <p class="currentAction text-xs text-orange-500">Mode: ${mode}</p>
  1269. `
  1270.  
  1271. document.querySelector('div#root').insertAdjacentElement('afterend', controlPanelElement)
  1272. } else {
  1273. controlPanel.querySelector('.currentPage').textContent = `Page: ${getPage()}`
  1274. controlPanel.querySelector('.currentAction').textContent = `Mode: ${mode}`
  1275. controlPanel.querySelector('.scriptState').textContent = scriptState
  1276. controlPanel.querySelector('.manualGold').textContent = manualGoldState
  1277. }
  1278. }
  1279.  
  1280. const calculateTTF = () => {
  1281. const resourceTrNodes = document.querySelectorAll('#root > div > div:not(#maintabs-container) > div > div > div > table:not(.hidden) > tbody > tr')
  1282. resourceTrNodes.forEach((row) => {
  1283. const cells = row.querySelectorAll('td')
  1284. const resourceName = cells[0].textContent.trim()
  1285. const resource = getResource(resourceName)
  1286. let ttf = ''
  1287.  
  1288. if (resource && resource.current < resource.max && resource.speed) {
  1289. ttf = resource.ttf ? resource.ttf.timeLong : resource.ttz.timeLong
  1290. }
  1291.  
  1292. if (!cells[3]) {
  1293. const ttfElement = document.createElement('td')
  1294. ttfElement.className = 'px-3 3xl:px-5 py-3 lg:py-2 3xl:py-3 whitespace-nowrap w-1/3 text-right'
  1295. ttfElement.textContent = ttf
  1296. row.appendChild(ttfElement)
  1297. } else {
  1298. cells[3].textContent = ttf
  1299. }
  1300. })
  1301. }
  1302.  
  1303. const calculateTippyTTF = () => {
  1304. let potentialResourcesToFillTable = document.querySelectorAll('div.tippy-box > div.tippy-content > div > div > table')
  1305. if (potentialResourcesToFillTable.length) {
  1306. potentialResourcesToFillTable = potentialResourcesToFillTable[0]
  1307. const rows = potentialResourcesToFillTable.querySelectorAll('tr')
  1308. rows.forEach((row) => {
  1309. const cells = row.querySelectorAll('td')
  1310. const resourceName = cells[0].textContent.trim()
  1311.  
  1312. const resource = getResource(resourceName)
  1313. if (resource) {
  1314. let ttf = '✅'
  1315.  
  1316. const target = numberParser.parse(
  1317. cells[1].textContent
  1318. .split(' ')
  1319. .shift()
  1320. .replace(/[^0-9KM\-,\.]/g, '')
  1321. .trim()
  1322. )
  1323.  
  1324. if (target > resource.max || resource.speed <= 0) {
  1325. ttf = 'never'
  1326. } else if (target > resource.current) {
  1327. ttf = formatTime(Math.ceil((target - resource.current) / resource.speed)).timeShort
  1328. }
  1329.  
  1330. if (!cells[2]) {
  1331. const ttfElement = document.createElement('td')
  1332. ttfElement.className = 'px-4 3xl:py-1 text-right'
  1333. ttfElement.textContent = ttf
  1334. row.appendChild(ttfElement)
  1335. } else {
  1336. cells[2].textContent = ttf
  1337. }
  1338. }
  1339. })
  1340. }
  1341. }
  1342.  
  1343. const checkMarketplaceAvailable = async () => {
  1344. let hasResourcesToTrade = false
  1345. let hasMarketplaceEnabled = false
  1346.  
  1347. resourcesToTrade.forEach((resName) => {
  1348. const res = getResource(resName)
  1349.  
  1350. if (res) {
  1351. hasResourcesToTrade = true
  1352. }
  1353. })
  1354.  
  1355. const navButtons = document.querySelectorAll('#main-tabs > div > button')
  1356. navButtons.forEach((button) => {
  1357. if (button.innerText.includes('Marketplace') && button.getAttribute('aria-selected') !== 'true') {
  1358. hasMarketplaceEnabled = true
  1359. }
  1360. })
  1361.  
  1362. marketPlaceAvailable = hasResourcesToTrade && hasMarketplaceEnabled
  1363. }
  1364.  
  1365. const tossACoinToYourClicker = () => {
  1366. if (cheatsOff) return
  1367. if (!haveManualResourceButtons) return
  1368. if (scriptPaused) return
  1369.  
  1370. const manualResources = ['Food', 'Wood', 'Stone']
  1371. const resourcesToClick = []
  1372. const buttonsToClick = []
  1373. const buttons = document.querySelectorAll(
  1374. '#root > div.flex.flex-wrap.w-full.mx-auto.p-2 > div.w-full.lg\\:pl-2 > div > div.order-2.flex.flex-wrap.gap-3 > button'
  1375. )
  1376.  
  1377. if (!buttons) {
  1378. haveManualResourceButtons = false
  1379. return
  1380. }
  1381.  
  1382. manualResources.forEach((resourceName) => {
  1383. const resource = getResource(resourceName)
  1384.  
  1385. if (resource && resource.current < resource.max && (!resource.speed || resource.speed <= 0)) {
  1386. resourcesToClick.push(resourceName)
  1387. }
  1388. })
  1389.  
  1390. buttons.forEach((button) => {
  1391. if (resourcesToClick.includes(button.innerText.trim())) {
  1392. buttonsToClick.push(button)
  1393. }
  1394. })
  1395.  
  1396. while (buttonsToClick.length) {
  1397. const buttonToClick = buttonsToClick.shift()
  1398. buttonToClick.click()
  1399. }
  1400. }
  1401.  
  1402. const checkToPlayMarket = () => {
  1403. if (cheatsOff) return
  1404.  
  1405. const page = getPage()
  1406.  
  1407. if (scriptPaused && manualGold && marketPlaceAvailable && !playingMarket && page === pages.MARKETPLACE) {
  1408. playMarket()
  1409. }
  1410.  
  1411. if (page !== pages.MARKETPLACE) {
  1412. playingMarket = false
  1413. }
  1414. }
  1415.  
  1416. const performRoutineTasks = () => {
  1417. calculateTTF()
  1418.  
  1419. if (!cheatsOff) {
  1420. checkMarketplaceAvailable()
  1421. managePanel()
  1422. checkToPlayMarket()
  1423. assignPopulation()
  1424. }
  1425. }
  1426.  
  1427. const performFastTasks = () => {
  1428. calculateTippyTTF()
  1429.  
  1430. if (!cheatsOff) {
  1431. if (haveManualResourceButtons) tossACoinToYourClicker()
  1432. }
  1433. }
  1434.  
  1435. window.setInterval(performRoutineTasks, 1000)
  1436. window.setInterval(performFastTasks, 100)
  1437.  
  1438. const loadSettingsFromLocalStorage = () => {
  1439. const TMH_scriptPaused = window.localStorage.getItem('TMH_scriptPaused')
  1440. const TMH_manualGold = window.localStorage.getItem('TMH_manualGold')
  1441. const TMH_cheatsOff = window.localStorage.getItem('TMH_cheatsOff')
  1442.  
  1443. if (TMH_cheatsOff) {
  1444. cheatsOff = JSON.parse(TMH_cheatsOff)
  1445. }
  1446.  
  1447. if (TMH_scriptPaused) {
  1448. scriptPaused = JSON.parse(TMH_scriptPaused)
  1449. }
  1450.  
  1451. if (TMH_manualGold) {
  1452. manualGold = JSON.parse(TMH_manualGold)
  1453. }
  1454. }
  1455. loadSettingsFromLocalStorage()
  1456.  
  1457. if (!cheatsOff) {
  1458. await sleep(5000)
  1459. takePageAction()
  1460.  
  1461. if (!scriptPaused) {
  1462. setTimeout(() => {
  1463. window.location.reload()
  1464. }, 60 * 60 * 1000)
  1465. }
  1466. }
  1467. })()