Janka Tietzova

A user script for The West, optimized Dobby2 for butt plugs and cake decorations.

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/512872/1465973/Janka%20Tietzova.js

  1. // ==UserScript==
  2. // @name Janka Tietzova
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.1.1
  5. // @description A user script for The West, optimized Dobby2 for butt plugs and cake decorations.
  6. // @author Chvostnatý Gábor
  7. // @include https://*.the-west.*/game.php*
  8. // @license MIT
  9. // @icon data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAAHdElNRQfoAwISKiXgp+5lAAAFKUlEQVRIx4WVy28cWRXGf+dWudvtdrc78TOjJJOHIUOiZDGLGbFAQUKDYMWfwGKGBRIrHmLBgoeGBRI7/gxACGmkEQiQYEZkCBNmnJB4jOPYcWx30u9HdXVVddU9LLr65Qhxpaq6p+rc853vfLfOlQ/vbqsxgjEGJ72MMTiOQUTGlzHTts7YxgjGmfg6jsGYqW8iTJyngo7GyFa1WBsDishsAiP3/2W78DLANHA8CDn6zz28epm18+fI5ZfIn7nAQnE1DQRiJokZI1MAw6crAgJjkJnsgedP7lP++A+4SUJ/UMcun6Vb22f9ypsUVi6C6DBAum56PQgCuIbTLCaOfa/N4f07nD9T4NLVTVDweh0afovKwT/JFZbJ5PII0+t4aW7kFMDESehWj3hxsEsQK5VGGysO7W5I7WmZ2tM9/NbRKf2YmY9MM/1hmrKi9DpVwiDk37snPNh+itdusP2kzO6TFxw93qdTeYZNEv7fMKczGdsKg7CP6whv3LjKGzc/h9rh/Pbr13AFWuXHxKHHJOfJUJ3M3dNbdoIIySAimxU06GK9ObqVDu6Cg9fvMJfL4nt1wm6VbL6EqqKaVkF1JqaZ3m4zlFRRG+InMUf1Fkmzy1Kti+kF1Hp9EjEMogi/U8PaZBxcpyioDt+ZmdRTR2xCMuiTyw5YW8lTqVY48dqEmxsc97t8uv0Y11FElaB1TNRrjbUZBVZVlOFzRhPVIVavXaZx8BGxV4EkZmV5CTeT5dH9BxwfP6ewtEDpTIFCYZFBp0z7ZIdEbRp8CkRBX9JEgDAi8/AzGtt/4oVtU280+fz5K1y6usm5V16h1aqze7zHfDZHoVike3BI6RDcM1fQ9Y2xNtNA7oxIfh/3V7+k9LvfUHQTovVF9FyJ1QubzGfnWSwWyQDB82cMtj6l3gjJ3d9j/aDCwh//jP+Td7HXb55iI8i9rT0VEcR1MXc+pPSddyj0fRwgEqG7kCW4uMb8pQsUvQTb6dIddAm7HsVnDfLAHBABXP8C0U/fJb79FYwIjjPs3mZaEHP3Dk7fRxAcgRzKai9gdecIHjwiONiFw30kDDhX7bIMZAUsQojQf7SN/OD7mI/vYh0Hq2CtTUFEwPeZ2/oXAsQiKIIzFI28tayftMgEMVE+x1K5zXwwGCaT/hs9gZYIrYN99Ec/ZO7997CdLlbBqCqIIPUacniAAj6QpD1UZNi+HYWlapvVozqLfjjuTQ6QCJRVaaqSiBB98gnxt97G/uzH2HZ7wsS0mphuBxA8oD3sLMNjQGX01w4TmmrjCnhiGHzxS8Sv3cAAAxFafo/mr39L+MEHuCMQp9MmE0WYlIWHsILi2CGQIFh00qUEVCBQxXv1Ihs//wVJPyD49jtw+IQI6K2VaFb3UiZRhPz1LzhhiIgwlzLopaULUCIUmyYQAYGCp3AMlC9dRtfWca9dI/nm27TyBZqrywTf+DLNuI2L4yAPH5K8/x4+MI8yQFAUD5gXIatKBkVT1oMUyEc4UYVCCTXO8BT82lsEtceYrJJsrFDthLgqguzvYRpVQqCvUBMoMSrTzG10CqAIMRACa4Uiqoq3/xm9nX+Q3VylHcYEmbNc/+ptXBKLXr5M762vEz64R7/n04oGnI2icdAk1cOkAAkyLtsc4DhKc+tvBCc7hKFPn3kWXn2d1269ycJiEVesRW/cwv/u9wg++j3hcYXk71s42ztYwKYcIgQzLBgJkKDECBnX5bB1jP/wDswtULx8i4tXbrK4soEYQxzH/BeqMKTC7KpG/gAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNC0wMy0wMlQxODo0MjozMSswMDowMC8Ty8sAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjQtMDMtMDJUMTg6NDI6MzErMDA6MDBeTnN3AAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0LTAzLTAyVDE4OjQyOjM3KzAwOjAwaotnkgAAAABJRU5ErkJggg==
  10. // @grant none
  11. // @downloadURL https://update.gf.qytechs.cn/scripts/497915/Zdenka%20Studenkova.user.js
  12. // @updateURL https://update.gf.qytechs.cn/scripts/497915/Zdenka%20Studenkova.meta.js
  13. // ==/UserScript==
  14.  
  15.  
  16.  
  17.  
  18. (function() {
  19. async function sleep(milliseconds) {
  20. await new Promise(r => setTimeout(r, milliseconds))
  21. }
  22.  
  23. function parseConsumableBonuses(bonuses) {
  24. const { energyText, motivationText, healthText, speedText, luckText, dropText, experienceText, moneyText } = Vajda.searchKeys[Vajda.language]
  25.  
  26. const result = {
  27. energy: 0,
  28. health: 0,
  29. motivation: 0,
  30. hasBuffs: false,
  31. buffs: {
  32. character: {
  33. luck: 0,
  34. money: 0,
  35. experience: 0,
  36. drop: 0
  37. },
  38. travel: 0
  39. }
  40. }
  41.  
  42. function getValue(bonus, bonusText) {
  43. return Number(bonus.toLowerCase().replace(bonusText.toLowerCase(), '').replace(' ', '').replace('%', '').replace('+', ''))
  44. }
  45. for (const bonus of bonuses) {
  46. if ( bonus.includes(energyText) ) {
  47. result.energy = getValue(bonus, energyText)
  48. continue
  49. }
  50. if ( bonus.includes(motivationText) ) {
  51. result.motivation = getValue(bonus, motivationText)
  52. continue
  53. }
  54.  
  55. if ( bonus.includes(healthText) ) {
  56. result.health = getValue(bonus, healthText)
  57. continue
  58. }
  59.  
  60. if ( bonus.includes(speedText) ) {
  61. result.buffs.travel = getValue(bonus, speedText)
  62. result.hasBuffs = true
  63. continue
  64. }
  65.  
  66. if ( bonus.includes(luckText) ) {
  67. result.buffs.character.luck = getValue(bonus, luckText)
  68. result.hasBuffs = true
  69. continue
  70. }
  71.  
  72. if ( bonus.includes(experienceText) ) {
  73. result.buffs.character.experience = getValue(bonus, experienceText)
  74. result.hasBuffs = true
  75. continue
  76. }
  77.  
  78. if ( bonus.includes(moneyText) ) {
  79. result.buffs.character.money = getValue(bonus, moneyText)
  80. result.hasBuffs = true
  81. continue
  82. }
  83.  
  84. if ( bonus.includes(dropText) ) {
  85. result.buffs.character.drop = getValue(bonus, dropText)
  86. result.hasBuffs = true
  87. }
  88. }
  89.  
  90. return result
  91. }
  92.  
  93.  
  94. class Job {
  95. constructor(x, y, id, groupId) {
  96. this.x = x
  97. this.y = y
  98. this.id = id
  99. this.groupId = groupId
  100. this.isSilver = false
  101. this.distances = []
  102. this.experience = 0
  103. this.money = 0
  104. this.motivation = 0
  105. this.stopMotivation = 75
  106. this.set = -1
  107. this.bestEquipment_ = undefined
  108. }
  109.  
  110. setIsSilver(val) {
  111. this.isSilver = val
  112. return this
  113. }
  114.  
  115. setExperience(val) {
  116. this.experience = val
  117. return this
  118. }
  119.  
  120. setMoney(val) {
  121. this.money = val
  122. return this
  123. }
  124.  
  125. setMotivation(valOrUpdater) {
  126. if ( typeof valOrUpdater === 'function' ) {
  127. this.motivation = valOrUpdater(this.motivation)
  128. } else {
  129. this.motivation = valOrUpdater
  130. }
  131.  
  132. this.motivation = Math.min(100, this.motivation)
  133.  
  134. return this
  135. }
  136.  
  137. setStopMotivation(val) {
  138. this.stopMotivation = val
  139. return this
  140. }
  141.  
  142. setSet(index) {
  143. this.set = index
  144. return this
  145. }
  146.  
  147. getDistances() {
  148. return this.distances
  149. }
  150.  
  151. async loadMotivation() {
  152. await Ajax.get('job', 'job', {jobId: this.id, x: this.x, y: this.y}, (r) => {
  153. this.motivation = r.motivation * 100
  154. })
  155.  
  156. return this.motivation
  157. }
  158.  
  159. /**
  160. * Calculate job distance to current character position
  161. */
  162. calculateDistance() {
  163. this.distance = GameMap.calcWayTime({x: this.x, y: this.y}, Character.position)
  164. return this.distance
  165. }
  166.  
  167. /**
  168. * Calculate job distance to other selected jobs
  169. */
  170. calculateJobDistances() {
  171. this.distances = []
  172. for ( const job of Vajda.addedJobs ) {
  173. this.distances.push(GameMap.calcWayTime({x: this.x, y: this.y}, {x: job.x, y: job.y}))
  174. }
  175. return this.distances
  176. }
  177.  
  178.  
  179. saveBestEquipment() {
  180. const skills = JobsModel.Jobs.find(j => j.id === this.id).get('skills')
  181. const set = west.item.Calculator.getBestSet(skills, this.id)
  182. const itemIds = set && set.getItems() || []
  183. this.bestEquipment_ = itemIds
  184. return itemIds
  185. }
  186.  
  187. get bestEquipment() {
  188. return this.bestEquipment_ === undefined ? this.saveBestEquipment() : this.bestEquipment_
  189. }
  190.  
  191.  
  192. getBestEquipment() {
  193. if (!Bag.loaded) {
  194. EventHandler.listen('inventory_loaded', function() {
  195. this.getBestEquipment()
  196. return EventHandler.ONE_TIME_EVENT
  197. })
  198. return
  199. }
  200. const items = Bag.getItemsByItemIds(this.bestEquipment)
  201. const result = []
  202.  
  203. for (const item of items) {
  204. const wearItem = Wear.get(item.getType())
  205. if (!wearItem || (wearItem && (wearItem.getItemBaseId() !== item.getItemBaseId() || wearItem.getItemLevel() < item.getItemLevel()))) {
  206. result.push(item)
  207. }
  208. }
  209. return result.map(item => item.obj.getId())
  210. }
  211. }
  212.  
  213. class Consumable {
  214. constructor(id, image, name) {
  215. this.id = id
  216. this.image = image
  217. this.name = name
  218. this.energy = 0
  219. this.motivation = 0
  220. this.health = 0
  221. this.isSelected_ = false
  222. this.count = 0
  223. }
  224.  
  225. isCakeDecoration() {
  226. return this.id === 53339000
  227. }
  228.  
  229.  
  230. removeOne() {
  231. this.count -= 1
  232.  
  233. if ( this.count === 0 ) {
  234. const consumables = Manager.consumables
  235. const index = consumables.findIndex(c => c.id === this.id)
  236. consumables.splice(index, 1)
  237. }
  238. return this
  239. }
  240.  
  241. setCount(valOrUpdater) {
  242. if ( typeof valOrUpdater === 'function' ) {
  243. this.count = valOrUpdater(this.count)
  244. } else {
  245. this.count = valOrUpdater
  246. }
  247.  
  248. this.count = Math.max(0, this.count)
  249. return this
  250. }
  251.  
  252. setEnergy(val) {
  253. this.energy = val
  254. return this
  255. }
  256.  
  257. setMotivation(val) {
  258. this.motivation = val
  259. return this
  260. }
  261.  
  262. setHealth(val) {
  263. this.health = val
  264. return this
  265. }
  266.  
  267. setIsSelected(isSelected) {
  268. this.isSelected_ = isSelected
  269. return this
  270. }
  271.  
  272. hasCooldown() {
  273. return this.energy > 0 || this.motivation > 0 || this.health > 0
  274. }
  275.  
  276. getBuffHTML() {
  277. return '<strong>No Buffs</strong>'
  278. }
  279.  
  280. get isSelected() {
  281. return this.isSelected_
  282. }
  283. }
  284.  
  285. class Buff extends Consumable {
  286. constructor(id, image, name, buffs) {
  287. super(id, image, name, buffs)
  288. this.buffs_ = buffs
  289. }
  290.  
  291. getBuffImage() {
  292. return `https://westsk.innogamescdn.com/images/buffs/${this.getBuffType()}.jpg`
  293. }
  294.  
  295. getBuffType() {
  296. return this.buffs_.travel === 0 ? 'character' : 'travel'
  297. }
  298.  
  299. canUseAsBuff() {
  300. return CharacterSkills.buffs[this.getBuffType()] === null && !this.hasCooldown()
  301. }
  302.  
  303. getBuffHTML() {
  304. const containerStyle = `'
  305. display: grid;
  306. grid-template-columns: 30px auto;
  307. '`
  308.  
  309. const imgContainerStyle = `'
  310. display: flex;
  311. padding-bottom: 5px;
  312. '`
  313.  
  314. const buffsContainerStyle = `'
  315. display: grid;
  316. grid-template-rows: repeat(auto-fill, 15px);
  317. transform: translateY(5px)
  318. '`
  319. const buffs = this.buffs.reduce((acc, b) => acc.concat(`<p>${b}</p>`), '')
  320.  
  321. const html = `
  322. <div style=${containerStyle}>
  323. <span style=${imgContainerStyle}>
  324. <img style=align-self:end width=25px height=25px src=${this.getBuffImage()} alt='Buff Image'>
  325. </span>
  326.  
  327. <span style=${buffsContainerStyle}>
  328. ${
  329. buffs
  330. }
  331. </span>
  332. </div>
  333. `
  334.  
  335. return html
  336. }
  337.  
  338. removeOne() {
  339. this.count -= 1
  340.  
  341. if ( this.count === 0 ) {
  342. const consumables = Manager.consumables
  343. const buffs = Manager.buffs
  344. let index = consumables.findIndex(c => c.id === this.id)
  345. if ( index !== -1 ) {
  346. consumables.splice(index, 1)
  347. return this
  348. }
  349. index = buffs.findIndex(b => b.id === this.id)
  350. if ( index !== -1 ) {
  351. buffs.splice(index, 1)
  352. if ( Manager.selectedBuffs.some(b => b.id === this.id) ) {
  353. Manager.selectedBuffs_[this.getBuffType()] = null
  354. }
  355. }
  356. }
  357. return this
  358. }
  359.  
  360. get isSelected() {
  361. return Manager.selectedBuffs.some(b => b.id === this.id) || this.isSelected_
  362. }
  363.  
  364.  
  365. get buffs() {
  366. if ( this.getBuffType() === 'travel' ) {
  367. return [`+${this.buffs_.travel}% speed`]
  368. }
  369.  
  370. const buffs = []
  371. for ( const buff in this.buffs_.character ) {
  372. if ( this.buffs_.character[buff] > 0 ) {
  373. buffs.push(`+${this.buffs_.character[buff]}% ${buff}`)
  374. }
  375. }
  376. return buffs
  377. }
  378. }
  379.  
  380.  
  381. class ConsumablesManager {
  382. selectedBuffs_ = {
  383. travel: null,
  384. character: null
  385. }
  386.  
  387. constructor() {
  388. this.consumables_ = []
  389. this.buffs_ = []
  390. this.isOptimized_ = false
  391. this.jobsLeftInRound_ = 0
  392. this.schedule_ = []
  393. this.selectedBuffs_ = {
  394. travel: null,
  395. character: null
  396. }
  397. }
  398.  
  399. async loadJobMotivation(updatedJobsMotivation = undefined) {
  400. let expectedJobCount = 0
  401. const uniqueJobsCount = Vajda.addedJobs.length
  402.  
  403. if ( updatedJobsMotivation !== undefined ) {
  404. expedtedJobCount = updatedJobsMotivation.reduce((acc, curr) => acc + curr, 0)
  405.  
  406. return { expectedJobCount, uniqueJobsCount }
  407. }
  408.  
  409. for ( const job of Vajda.addedJobs ) {
  410. expectedJobCount += Math.max(await job.loadMotivation() - job.stopMotivation, 0)
  411.  
  412. await sleep(500)
  413. }
  414.  
  415. return { expectedJobCount, uniqueJobsCount }
  416. }
  417.  
  418. async createSchedule(updatedJobsMotivation) {
  419. const bottlePlugs = this.consumables.find(c => c.id === 52871000)
  420.  
  421. //in case the game runs in the background and the job to travel to is not canceled we gonna need extra energy point
  422. //this is unlikely to happen but the energy wont go to waste anyway so why the fuck not
  423. const { expectedJobCount, uniqueJobsCount } = await this.loadJobMotivation(updatedJobsMotivation)
  424.  
  425. this.jobsLeftInRound = expectedJobCount
  426. const availableEnergy = Character.energy
  427. const energyToFill = expectedJobCount + uniqueJobsCount - availableEnergy
  428. const refillCount = Math.ceil(
  429. energyToFill / ( bottlePlugs.energy / 100 * Character.maxEnergy )
  430. )
  431.  
  432. //use plugs when n jobs left in round
  433. const schedule = []
  434.  
  435. for ( let i = 0; i < refillCount; i++ ) {
  436. //40 15s jobs in consumable cooldown
  437. schedule.push(40 + i*40)
  438. }
  439.  
  440. this.schedule_ = schedule
  441. return schedule
  442. }
  443.  
  444. isScheduledRefill() {
  445. return this.isOptimized_ && this.refillsLeft > 0 && this.jobsLeftInRound <= this.schedule.at(-1)
  446. }
  447.  
  448. async checkSchedule(jobCount) {
  449. const bottlePlug = this.consumables.find(c => c.id === 52871000)
  450.  
  451. for ( let i = 0; i < jobCount; i++ ) {
  452. this.jobsLeftInRound = p => p - 1
  453. if ( this.isScheduledRefill() ) {
  454. //the use of consumable blocks the start of new jobs for a short amount of time, so this sleep exists to prevent that
  455. await sleep(10000)
  456. this.useConsumableOrWaitForCooldown(bottlePlug)
  457. this.schedule.pop()
  458. this.jobsLeftInRound = p => p - (jobCount - i - 1)
  459. return
  460. }
  461. }
  462.  
  463. if ( Character.energy - jobCount <= 10 ) {
  464. //same here
  465. await sleep(10000)
  466. this.useConsumableOrWaitForCooldown(bottlePlug)
  467. this.schedule.pop()
  468. }
  469. }
  470.  
  471. canUseConsumable(consumable) {
  472. if ( consumable instanceof Buff ) {
  473. return consumable.canUseAsBuff()
  474. }
  475.  
  476. if ( BuffList.cooldowns[consumable.id] !== undefined && BuffList.cooldowns[consumable.id].time > new ServerDate().getTime() ) {
  477. return false
  478. }
  479. return true
  480. }
  481.  
  482. findProperConsumable(motivationMissing, energyMissing, averageMotivationMissing) {
  483. const consumablesPool = this.getSelectedConsumables()
  484.  
  485. function betterEnergy(item1, item2) {
  486. let distanceItem1 = Math.abs(energyMissing - item1.energy)
  487. let distanceItem2 = Math.abs(energyMissing - item2.energy)
  488. return (distanceItem1 < distanceItem2 ) ? -1 : (distanceItem1 > distanceItem2) ? 1 : 0
  489. }
  490. function betterMotivation(item1, item2) {
  491. let distanceItem1 = Math.abs(averageMotivationMissing - item1.motivation)
  492. let distanceItem2 = Math.abs(averageMotivationMissing - item2.motivation)
  493. return (distanceItem2 < distanceItem1) ? item2 : item1
  494. }
  495. function findMotivationConsume(consumes) {
  496. let consumeToChoose = null
  497. for ( let i = 0; i < consumes.length; i++ ) {
  498. if ( consumeToChoose === null && consumes[i].motivation !== 0) {
  499. consumeToChoose = consumes[i]
  500. continue
  501. }
  502. if ( consumeToChoose !== null && consumes[i].motivation !== 0) {
  503. consumeToChoose = betterMotivation(consumeToChoose, consumables[i])
  504. }
  505. }
  506. return consumeToChoose
  507. }
  508. function findHealthConsume(consumes) {
  509. for ( let i = 0; i < consumes.length; i++ ) {
  510. if ( consumes[i].health !== 0 ) {
  511. return consumes[i]
  512. }
  513. }
  514. return null
  515. }
  516.  
  517. if ( consumablesPool.length === 0 ) return null
  518. const consumables = consumablesPool.sort(betterEnergy)
  519. if ( Vajda.settings.addEnergy && energyMissing === 100 ) {
  520. return consumables[0]
  521. }
  522. if ( Vajda.settings.addMotivation && motivationMissing === Vajda.addedJobs.length ) {
  523. return findMotivationConsume(consumables)
  524. }
  525. if ( Vajda.settings.addHealth && Vajda.isHealthBelowLimit() ) {
  526. if ( this.isOptimized ) {
  527. this.schedule.pop()
  528. }
  529. return findHealthConsume(consumables)
  530. }
  531. }
  532.  
  533. async useConsumable(consumable) {
  534. const item = Bag.getItemByItemId(consumable.id)
  535. item.showCooldown()
  536.  
  537. if ( Vajda.shouldEquipHealthSet(consumable) )
  538. await Vajda.equipSet(Vajda.healthSet)
  539.  
  540. ItemUse.doIt(consumable.id)
  541. consumable.removeOne()
  542. while(true) {
  543. if ( !this.canUseConsumable(consumable) ) {
  544. $('.tw2gui_dialog_framefix').remove()
  545. break
  546. }
  547. await sleep(1)
  548. }
  549.  
  550. Vajda.currentState = 1
  551. }
  552.  
  553. async useConsumableOrWaitForCooldown(consumableOrId, isSync = false) {
  554. const consumable = consumableOrId instanceof Consumable ? consumableOrId : this.getSelectedConsumables().find(c => c.id === consumableOrId)
  555. if ( consumable === undefined ) {
  556. return false
  557. }
  558.  
  559. Vajda.currentState = 2
  560.  
  561. while (true) {
  562. if ( consumable.hasCooldown() === false || this.canUseConsumable(consumable) ) {
  563. break
  564. }
  565.  
  566. if ( !Vajda.isRunning ) {
  567. break
  568. }
  569.  
  570. await sleep(1000)
  571. }
  572.  
  573. await this.useConsumable(consumable)
  574. isSync && Vajda.run()
  575. }
  576.  
  577. isConsumableAdded (item) {
  578. if ( item === undefined )
  579. return true
  580. for ( const consumable of this.consumables_ ) {
  581. if ( consumable.id === item.obj.item_id ) {
  582. return true
  583. }
  584. }
  585. for ( const buff of this.buffs_ ) {
  586. if ( buff.id === item.obj.item_id ) {
  587. return true
  588. }
  589. }
  590. return false
  591. }
  592.  
  593. useBuff(type) {
  594. const buff = this.selectedBuffs_[type]
  595.  
  596. if ( buff?.canUseAsBuff() ) {
  597. this.useConsumable(buff)
  598. }
  599. }
  600.  
  601. addNewConsumable(item) {
  602. if ( this.isConsumableAdded(item) ) {
  603. return
  604. }
  605. const { energy, motivation, health, hasBuffs, buffs } = parseConsumableBonuses(item.obj.usebonus)
  606.  
  607. if ( health === 0 && motivation === 0 && energy === 0 && !hasBuffs )
  608. return
  609.  
  610. if ( hasBuffs ) {
  611. const buff = new Buff(item.obj.item_id, item.obj.image, item.obj.name, buffs)
  612. .setEnergy(energy)
  613. .setMotivation(motivation)
  614. .setHealth(health)
  615. .setCount(item.count)
  616. return buff.hasCooldown() ? this.consumables_.push(buff) : this.buffs_.push(buff)
  617. }
  618. const consumable = new Consumable(item.obj.item_id, item.obj.image, item.obj.name)
  619. .setEnergy(energy)
  620. .setMotivation(motivation)
  621. .setHealth(health)
  622. .setCount(item.count)
  623. this.consumables.push(consumable)
  624. }
  625.  
  626. hasEnoughPlugsAndDecorations() {
  627. const bottlePlugs = this.consumables.find(c => c.id === 52871000)
  628. const decorations = this.consumables.find(c => c.id === 53339000)
  629.  
  630. if ( !bottlePlugs || !decorations ) {
  631. new UserMessage("No plugs or decorations were found, defaulting back to selected consumables", UserMessage.TYPE_HINT).show()
  632. this.isOptimized_ = false
  633. return false
  634. }
  635. return true
  636. }
  637.  
  638. getSelectedConsumables() {
  639. if ( this.isOptimized_ ) {
  640. const bottlePlugs = this.consumables.find(c => c.id === 52871000)
  641. const decorations = this.consumables.find(c => c.id === 53339000)
  642.  
  643. return [bottlePlugs, decorations]
  644. } else {
  645. return this.consumables.filter(c => c.isSelected === true)
  646. }
  647. }
  648.  
  649. addSelectedConsumable(val) {
  650. if ( typeof val === 'number' )
  651. this.consumables.at(val).isSelected = true
  652.  
  653. if ( val instanceof Consumable )
  654. this.consumables.find(c => c.id === val.id).isSelected = true
  655. }
  656.  
  657. get schedule() {
  658. return this.schedule_
  659. }
  660.  
  661. set schedule(val) {
  662. this.schedule_ = val
  663. }
  664.  
  665. get consumables() {
  666. return this.consumables_
  667. }
  668.  
  669. set consumables(val) {
  670. this.consumables_ = val
  671. }
  672.  
  673. get isOptimized() {
  674. return this.isOptimized_
  675. }
  676.  
  677. set isOptimized(valOrUpdater) {
  678. if ( typeof valOrUpdater === 'function' ) {
  679. this.isOptimized_ = valOrUpdater(this.isOptimized_)
  680. } else {
  681. this.isOptimized_ = valOrUpdater
  682. }
  683. }
  684.  
  685. get jobsLeftInRound() {
  686. return this.jobsLeftInRound_
  687. }
  688. set jobsLeftInRound(valOrUpdater) {
  689. if ( typeof valOrUpdater === 'function' ) {
  690. this.jobsLeftInRound_ = valOrUpdater(this.jobsLeftInRound_)
  691. } else {
  692. this.jobsLeftInRound_ = valOrUpdater
  693. }
  694. }
  695.  
  696. get refillsLeft() {
  697. return this.schedule.length
  698. }
  699.  
  700. get buffs() {
  701. return this.buffs_
  702. }
  703.  
  704. get selectedBuffs() {
  705. const res = []
  706. for ( const type in this.selectedBuffs_ ) {
  707. this.selectedBuffs_[type] && res.push(this.selectedBuffs_[type])
  708. }
  709.  
  710. return res
  711. }
  712.  
  713. set selectedBuffs(buff) {
  714. const type = buff.getBuffType()
  715. if ( this.selectedBuffs_[type]?.id === buff.id ) {
  716. this.selectedBuffs_[type] = null
  717.  
  718. return
  719. }
  720. this.selectedBuffs_[type] = buff
  721. new UserMessage(`New ${type} buff selected`, UserMessage.TYPE_SUCCESS).show()
  722. }
  723. }
  724.  
  725.  
  726. class ActivityObserver {
  727. constructor() {
  728. const fiveMinutes = 5 * 60 * 1000
  729. this.activityCheckTimeout_ = null
  730. this.refreshCount = 0
  731. this._isEnabled = false
  732. this.timeOut_ = fiveMinutes
  733. this.selectedConsumables = null
  734. }
  735.  
  736. saveTempCookies() {
  737. const selectedConsumables = Manager.consumables.reduce((acc, c) => {
  738. c.isSelected && acc.push(c.id)
  739. return acc
  740. }, [])
  741. const timeOut = this.timeOut_
  742. const buffs = {
  743. travel: Manager.selectedBuffs_.travel?.id || null,
  744. character: Manager.selectedBuffs_.character?.id || null
  745. }
  746. const settings = {
  747. statistics: Vajda.statistics,
  748. selectedConsumables,
  749. buffs,
  750. timeOut,
  751. direction: Vajda.direction,
  752. currentJob: Vajda.currentJob,
  753. refreshCount: this.refreshCount + 1,
  754. schedule: Manager.schedule,
  755. jobsLeftInRound: Manager.jobsLeftInRound,
  756. travelSet: Vajda.travelSet,
  757. jobSet: Vajda.jobSet,
  758. healthSet: Vajda.healthSet
  759. }
  760. const expiracyDateTemporary = new Date()
  761. const hour = expiracyDateTemporary.getHours()
  762. expiracyDateTemporary.setHours(2,0,0)
  763.  
  764. if ( hour > 2 )
  765. expiracyDateTemporary.setDate(expiracyDateTemporary.getDate() + 1)
  766.  
  767. document.cookie = `vajdasession=${JSON.stringify(settings)};expires=${expiracyDateTemporary.toGMTString()};`
  768. }
  769.  
  770. getTempCookies() {
  771. const cookies = document.cookie.split("=")
  772. for ( let i = 0; i < cookies.length; i++ ) {
  773. if ( cookies[i].includes("vajdasession") ) {
  774. const {
  775. timeOut, schedule, selectedConsumables, buffs, jobsLeftInRound, refreshCount, ...vajdaSettings
  776. } = JSON.parse(cookies[i+1].split(";")[0])
  777.  
  778. this.selectedConsumables = selectedConsumables
  779. this.buffs = buffs
  780. this.refreshCount = refreshCount
  781. this.timeOut_ = timeOut
  782. this.isEnabled = true
  783. Manager.jobsLeftInRound = jobsLeftInRound
  784. Manager.schedule = schedule
  785. Vajda = {...Vajda, ...vajdaSettings, isRunning: true}
  786. document.cookie = 'vajdasession=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
  787. return true
  788. }
  789. }
  790. return false
  791. }
  792.  
  793. restartSession() {
  794. if ( Vajda.currentState === 2 ) {
  795. this.start()
  796. return
  797. }
  798.  
  799. this.saveTempCookies()
  800. location.reload()
  801. }
  802.  
  803. resumeSession() {
  804. Vajda.findAllConsumables()
  805. if ( !this.getTempCookies() ) return
  806. Vajda.createWindow(false)
  807. Vajda.run()
  808. }
  809.  
  810. start(forceStart = false) {
  811. if ( !this.isEnabled && !forceStart ) return
  812.  
  813. clearTimeout(this.activityCheckTimeout_)
  814. this.activityCheckTimeout_ = setTimeout(this.restartSession.bind(this), this.timeOut_)
  815. }
  816.  
  817. stop() {
  818. this.isEnabled = false
  819. if ( this.activityCheckTimeout_ !== null )
  820. clearTimeout(this.activityCheckTimeout_)
  821. this.activityCheckTimeout_ = null
  822. }
  823.  
  824. getTimeOut(convertToMinutes) {
  825. if ( convertToMinutes ) {
  826. return this.timeOut_ / 1000 / 60
  827. }
  828. return this.timeOut_
  829. }
  830.  
  831. get isEnabled() {
  832. return this._isEnabled
  833. }
  834.  
  835. set isEnabled(valOrUpdater) {
  836. if ( typeof valOrUpdater === 'function' ) {
  837. this._isEnabled = valOrUpdater(this._isEnabled)
  838. } else {
  839. this._isEnabled = valOrUpdater
  840. }
  841. }
  842.  
  843. set timeOut(val) {
  844. this.timeOut_ = Math.max(Number(val) * 60 * 1000, 2.5 * 60 * 1000)
  845. }
  846. }
  847.  
  848. window.Manager = new ConsumablesManager()
  849. window.Observer = new ActivityObserver()
  850.  
  851.  
  852. Vajda = {
  853. addedJobs: [],
  854. allJobs: [],
  855. addedJobTablePosition: {
  856. content: "0px",
  857. scrollbar:"0px"
  858. },
  859. consumableSelection: {
  860. energy: false,
  861. motivation: false,
  862. health: false,
  863. hideBuffs: false
  864. },
  865. consumableTablePosition: {
  866. content: '0px',
  867. scrollbar: '0px'
  868. },
  869. consumableUsed: [],
  870. currentJob: {
  871. job: 0,
  872. direction: true
  873. },
  874. currentState: 0,
  875. healthSet: -1,
  876. language: "",
  877. isLoaded: false,
  878. isRunning: false,
  879. jobFilter: {
  880. filterOnlySilver: false,
  881. filterNoSilver: false,
  882. filterCenterJobs: false,
  883. filterJob: ""
  884. },
  885. jobSet: -1,
  886. jobsLoaded: false,
  887. jobTablePosition: {
  888. content: "0px",
  889. scrollbar: "0px"
  890. },
  891. lastJobStartTime: undefined,
  892. states: [
  893. 'Idle',
  894. 'Running',
  895. 'Waiting for a consumable cooldown',
  896. 'Calculating optimal route'
  897. ],
  898. statistics: {
  899. sessionJobsCount: 0,
  900. sessionXpCount: 0,
  901. sessionMoneyCount: 0,
  902. totalJobsCount: 0,
  903. totalXpCount: 0,
  904. totalMoneyCount: 0
  905. },
  906. selectedSet: 0,
  907. sets: null,
  908. settings: {
  909. addEnergy: false,
  910. addMotivation: false,
  911. addHealth: false,
  912. healthStop: 10,
  913. setWearDelay: 5,
  914. jobDelayMin: 0,
  915. jobDelayMax: 0,
  916. addDeposit: {
  917. isEnabled: false,
  918. limit: NaN
  919. }
  920. },
  921. sortJobTableXp:0,
  922. sortJobTableDistance:0,
  923. travelSet: -1,
  924. regenerationSet: -1,
  925. window: null,
  926. searchKeys: {
  927. "en_DK":{
  928. energy:"Energy",
  929. energyText:"Energy increase:",
  930. motivation:"Work motivation",
  931. motivationText:"Work motivation increase:",
  932. health: "Health point bonus",
  933. healthText:"Health point bonus:"
  934. },
  935. "sk_SK": {
  936. energy:"Energie",
  937. energyText:"Zvýšenie energie:",
  938. motivation:"Pracovnej motivácie",
  939. motivationText:"Zvýšenie pracovnej motivácie:",
  940. health: "Bonus bodov zdravia",
  941. healthText:"Bonus bodov zdravia:",
  942. speedText: "Rýchlosť",
  943. experience: "skúseností",
  944. experienceText: "Skúseností z práce, duelov a boja o pevnosť",
  945. money: "peňazí",
  946. moneyText: "Peňazí z práce a duelov",
  947. luck: "šťastie",
  948. luckText: "Vylepšené šťastie",
  949. drop: "produktu",
  950. dropText: "Vylepšenie šance na získanie produktu"
  951. },
  952. "cs_CZ":{
  953. energy:"Energie",
  954. energyText:"Zvýšení energie:",
  955. motivation:"Pracovní motivace",
  956. motivationText:"Zvýšení pracovní motivace:",
  957. health: "Bonus zdraví",
  958. healthText:"Bonus zdraví:",
  959. speedText: "Rychlost",
  960. experience: "zkušeností",
  961. experienceText: "zkušeností z prací, duelů a bitev o pevnost",
  962. money: "prací",
  963. moneyText: "$ z prací a duelů",
  964. luck: "štěstí",
  965. luckText: "Vyšší šance na štěstí",
  966. drop: "produktu",
  967. dropText: "Vylepšené šance nálezu produktu"
  968. },
  969. "hu_HU":{
  970. energy:"Energia növekedése:",
  971. energyText:"Energia növekedése:",
  972. motivation:"Munka motiváció növelése:",
  973. motivationText:"Munka motiváció növelése:",
  974. health: "Életerő bónusz",
  975. healthText:"Életerő bónusz:"
  976. },
  977. "pl_PL":{
  978. energy:"Wzrost energii:",
  979. energyText:"Wzrost energii:",
  980. motivation:"Zwiększenie motywacji do pracy:",
  981. motivationText:"Zwiększenie motywacji do pracy:",
  982. health: "Bonus Punktów życia:",
  983. healthText:"Bonus Punktów życia:"
  984. },
  985. "ro_RO":{
  986. energy:"Energie mărită:",
  987. energyText:"Energie mărită:",
  988. motivation:"Creştere a motivaţiei de muncă:",
  989. motivationText:"Creştere a motivaţiei de muncă:",
  990. health: "Puncte de viaţă:",
  991. healthText:"Puncte de viaţă:"
  992. }
  993. }
  994. }
  995.  
  996.  
  997. Vajda.isNumber = function(potentialNumber) {
  998. return Number.isInteger(parseInt(potentialNumber))
  999. }
  1000.  
  1001. Vajda.RNG = function(min, max) {
  1002. let minN = Math.min(min, max)
  1003. let maxN = Math.max(min, max)
  1004.  
  1005. let number = Math.floor((minN + Math.random() * (maxN - minN + 1)))
  1006. return number
  1007. }
  1008.  
  1009.  
  1010. Vajda.isAllowedToDepositMoney = function() {
  1011. const hasMoreMoneyThanLimit = Vajda.settings.addDeposit.limit <= Character.money
  1012. const hasHomeTown = Character.homeTown.town_id !== 0
  1013.  
  1014. if ( hasHomeTown == false ) {
  1015. new UserMessage("You don't have a home town", UserMessage.TYPE_HINT).show()
  1016. return false
  1017. }
  1018. return Vajda.settings.addDeposit.isEnabled && hasMoreMoneyThanLimit
  1019. }
  1020.  
  1021.  
  1022. Vajda.getCookies = function() {
  1023. const cookies = document.cookie.split("=")
  1024. for ( let i = 0; i < cookies.length; i++ ) {
  1025. if ( cookies[i].includes("vajdatemporary") ) {
  1026. const obj = cookies[i+1].split(";")
  1027. const tempObject = JSON.parse(obj[0])
  1028. const tmpAddedJobs = tempObject.addedJobs
  1029.  
  1030. for ( const job of tmpAddedJobs ) {
  1031. const newJob = new Job(job.x, job.y, job.id, job.groupId)
  1032. newJob
  1033. .setIsSilver(job.isSilver)
  1034. .setExperience(job.experience)
  1035. .setMoney(job.money)
  1036. .setMotivation(job.motivation)
  1037. .setStopMotivation(job.stopMotivation)
  1038. .setSet(job.set)
  1039. Vajda.addedJobs.push(newJob)
  1040. }
  1041.  
  1042. Vajda.travelSet = tempObject.travelSet
  1043. Vajda.jobSet = tempObject.jobSet
  1044. Vajda.healthSet = tempObject.healthSet
  1045. Vajda.currentJob = tempObject.currentJob
  1046. Vajda.setSetForAllJobs()
  1047. }
  1048. if ( cookies[i].includes("vajdapermanent") ) {
  1049. const obj = cookies[i+1].split(";")
  1050. const permanentObject = JSON.parse(obj[0])
  1051. const { isOptimized, isEnabled, timeOut, ...settings } = permanentObject.settings
  1052.  
  1053. Manager.isOptimized = !!isOptimized
  1054. Observer.isEnabled = !!isEnabled
  1055. Observer.timeOut = timeOut || 5
  1056. Vajda.settings = settings
  1057. if ( !settings.addDeposit ) {
  1058. Vajda.settings.addDeposit = {
  1059. isEnabled: false,
  1060. limit: NaN
  1061. }
  1062. }
  1063. Vajda.statistics.totalJobsCount = Math.floor(permanentObject.totalJobs)
  1064. Vajda.statistics.totalXpCount = permanentObject.totalXp
  1065. Vajda.statistics.totalMoneyCount = permanentObject.totalMoney
  1066. }
  1067. }
  1068. }
  1069.  
  1070. Vajda.setCookies = function() {
  1071. let expiracyDateTemporary = new Date()
  1072. let hour = expiracyDateTemporary.getHours()
  1073. expiracyDateTemporary.setHours(2,0,0)
  1074. if ( hour > 2 )
  1075. expiracyDateTemporary.setDate(expiracyDateTemporary.getDate() + 1)
  1076.  
  1077. const addedJobs = Vajda.addedJobs.map(j => ({
  1078. x: j.x,
  1079. y: j.y,
  1080. id: j.id,
  1081. groupId: j.groupId,
  1082. isSilver: j.isSilver,
  1083. experience: j.experience,
  1084. money: j.money,
  1085. motivation: j.motivation,
  1086. stopMotivation: j.stopMotivation,
  1087. set: j.set
  1088. }))
  1089. let temporaryObject = {
  1090. addedJobs,
  1091. travelSet: Vajda.travelSet,
  1092. jobSet: Vajda.jobSet,
  1093. healthSet: Vajda.healthSet,
  1094. currentJob: Vajda.currentJob
  1095. }
  1096. let expiracyDatePernament = new Date()
  1097. expiracyDatePernament.setDate(expiracyDatePernament.getDate() + 360000)
  1098. let pernamentObject = {
  1099. settings: {...Vajda.settings, isOptimized: Manager.isOptimized, isEnabled: Observer.isEnabled, timeOut: Observer.getTimeOut(true)},
  1100. totalJobs: Vajda.statistics.totalJobsCount,
  1101. totalXp: Vajda.statistics.totalXpCount,
  1102. totalMoney: Vajda.statistics.totalMoneyCount
  1103. }
  1104. const jsonTemporary = JSON.stringify(temporaryObject)
  1105. const jsonPernament = JSON.stringify(pernamentObject)
  1106. document.cookie = `vajdatemporary=${jsonTemporary};expires=${expiracyDateTemporary.toGMTString()};`
  1107. document.cookie = `vajdapermanent=${jsonPernament};expires=${expiracyDatePernament.toGMTString()};`
  1108. }
  1109.  
  1110. Vajda.shouldEquipHealthSet = function(consumable) {
  1111. if ( !consumable.hasCooldown() ) {
  1112. return false
  1113. }
  1114.  
  1115. if ( Manager.isOptimized ) {
  1116. return false
  1117. }
  1118.  
  1119. return consumable.health > 0 && Vajda.healthSet > -1
  1120. }
  1121.  
  1122.  
  1123. Vajda.parseConsumableBonuses = function(bonuses) {
  1124. let getBonus = (text,type) => {
  1125. switch(type) {
  1126. case 0:
  1127. text = text.replace(Vajda.searchKeys[Vajda.language].energyText,"")
  1128. break
  1129. case 1:
  1130. text = text.replace(Vajda.searchKeys[Vajda.language].motivationText,"")
  1131. break
  1132. case 2:
  1133. text = text.replace(Vajda.searchKeys[Vajda.language].healthText,"")
  1134. break
  1135. }
  1136. text = text.slice(1)
  1137. text = text.replace("%","")
  1138. return parseInt(text)
  1139. }
  1140. let result = Array(3).fill(0)
  1141. for ( let i = 0 ; i < bonuses.length; i++ ) {
  1142. let type = -1
  1143. if ( bonuses[i].includes(Vajda.searchKeys[Vajda.language].energyText) ) {
  1144. type = 0
  1145. }else if ( bonuses[i].includes(Vajda.searchKeys[Vajda.language].motivationText) ) {
  1146. type = 1
  1147. }else if ( bonuses[i].includes(Vajda.searchKeys[Vajda.language].healthText) ) {
  1148. type = 2
  1149. }
  1150. if ( type !=-1 )
  1151. result[type] = getBonus(bonuses[i],type)
  1152.  
  1153. }
  1154. return result
  1155. }
  1156.  
  1157. Vajda.findAllConsumables = function() {
  1158. if ( Vajda.searchKeys[Vajda.language] === undefined ) return
  1159. const energyConsumables = Bag.search(Vajda.searchKeys[Vajda.language].energy)
  1160. for ( const consumable of energyConsumables ) {
  1161. Manager.addNewConsumable(consumable)
  1162. }
  1163.  
  1164. const motivationConsumables = Bag.search(Vajda.searchKeys[Vajda.language].motivation)
  1165. for ( const consumable of motivationConsumables ) {
  1166. Manager.addNewConsumable(consumable)
  1167. }
  1168.  
  1169. const healthConsumables = Bag.search(Vajda.searchKeys[Vajda.language].health)
  1170. for ( const consumable of healthConsumables ) {
  1171. Manager.addNewConsumable(consumable)
  1172. }
  1173.  
  1174. const speedConsumables = Bag.search(Vajda.searchKeys[Vajda.language].speedText)
  1175. for ( const consumable of speedConsumables ) {
  1176. if ( consumable.obj.usetype !== 'none' ) {
  1177. Manager.addNewConsumable(consumable)
  1178. }
  1179. }
  1180.  
  1181. const luckConsumables = Bag.search(Vajda.searchKeys[Vajda.language].luck)
  1182. for ( const consumable of luckConsumables ) {
  1183. if ( consumable.obj.usetype !== 'none' ) {
  1184. Manager.addNewConsumable(consumable)
  1185. }
  1186. }
  1187.  
  1188. const experienceConsumables = Bag.search(Vajda.searchKeys[Vajda.language].experience)
  1189. for ( const consumable of experienceConsumables ) {
  1190. if ( consumable.obj.usetype !== 'none' ) {
  1191. Manager.addNewConsumable(consumable)
  1192. }
  1193. }
  1194.  
  1195. const moneyConsumables = Bag.search(Vajda.searchKeys[Vajda.language].money)
  1196. for ( const consumable of moneyConsumables ) {
  1197. if ( consumable.obj.usetype !== 'none' ) {
  1198. Manager.addNewConsumable(consumable)
  1199. }
  1200. }
  1201.  
  1202. const dropConsumables = Bag.search(Vajda.searchKeys[Vajda.language].drop)
  1203. for ( const consumable of dropConsumables ) {
  1204. if ( consumable.obj.usetype !== 'none' ) {
  1205. Manager.addNewConsumable(consumable)
  1206. }
  1207. }
  1208.  
  1209. Observer.selectedConsumables?.forEach(id => {
  1210. Manager.consumables.find(c => c.id === id).setIsSelected(true)
  1211. })
  1212.  
  1213. for ( const type in Observer.buffs ) {
  1214. Manager.selectedBuffs_[type] = Manager.buffs_.find(b => b.id === Observer.buffs[type]) || null
  1215. }
  1216. Observer.selectedConsumables = null
  1217. Observer.buffs = null
  1218. }
  1219.  
  1220. Vajda.filterConsumables = function(energy, motivation, health, hideBuffs) {
  1221. const result = hideBuffs ? [] : [...Manager.buffs]
  1222.  
  1223. for ( const consumable of Manager.consumables ) {
  1224. if ( energy && consumable.energy === 0 ) {
  1225. continue
  1226. }
  1227.  
  1228. if ( motivation && consumable.motivation === 0 ) {
  1229. continue
  1230. }
  1231.  
  1232. if ( health && consumable.health === 0 ) {
  1233. continue
  1234. }
  1235. result.push(consumable)
  1236. }
  1237.  
  1238. return result
  1239. }
  1240.  
  1241. Vajda.changeConsumableSelection = function(id, isSelected) {
  1242. Manager.consumables.find(c => c.id === id)?.setIsSelected(isSelected)
  1243. }
  1244.  
  1245. Vajda.changeSelectionAllConsumables = function(selected) {
  1246. for ( const consumable of Manager.consumables ) {
  1247. consumable.setIsSelected(selected)
  1248. }
  1249. }
  1250.  
  1251. Vajda.loadJobs = function() {
  1252. if ( !Vajda.jobsLoaded ) {
  1253. new UserMessage("Loading...", UserMessage.TYPE_HINT).show()
  1254. let index = 0
  1255. let currentLength = 0
  1256. let maxLength = 299
  1257. Ajax.get('map', 'get_minimap', {}, function(r) {
  1258. var tiles = []
  1259. var jobs = []
  1260.  
  1261. for ( let townNumber in r.towns ) {
  1262. if ( r.towns[townNumber].town_id === Character.homeTown.town_id ) {
  1263. Vajda.homeTown = r.towns[townNumber]
  1264. break
  1265. }
  1266. }
  1267.  
  1268.  
  1269. for ( let jobGroup in r.job_groups ) {
  1270. const groupId = parseInt(jobGroup)
  1271. let group = r.job_groups[jobGroup]
  1272. let jobsGroup = JobList.getJobsByGroupId(groupId)
  1273.  
  1274. for ( let tilecoord = 0; tilecoord < group.length; tilecoord++ ) {
  1275. let xCoord = Math.floor(group[tilecoord][0]/GameMap.tileSize)
  1276. let yCoord = Math.floor(group[tilecoord][1]/GameMap.tileSize)
  1277. if ( currentLength == 0 ) {
  1278. tiles[index] = []
  1279. }
  1280.  
  1281. tiles[index].push([xCoord,yCoord])
  1282. currentLength++
  1283.  
  1284. if ( currentLength === maxLength ) {
  1285. currentLength = 0
  1286. index++
  1287. }
  1288.  
  1289. for ( let i = 0; i < jobsGroup.length; i++ ) {
  1290. jobs.push(new Job(group[tilecoord][0],group[tilecoord][1],jobsGroup[i].id, groupId))
  1291. }
  1292. }
  1293. }
  1294. let toLoad = tiles.length
  1295. let loaded = 0
  1296. for ( let blocks = 0; blocks < tiles.length; blocks++ ) {
  1297. GameMap.Data.Loader.load(tiles[blocks], function() {
  1298. loaded++
  1299. if ( loaded === toLoad ) {
  1300. Vajda.jobsLoaded = true
  1301. Vajda.allJobs = jobs
  1302. Vajda.findAllConsumables()
  1303. Vajda.createWindow()
  1304. }
  1305. })
  1306. }
  1307. })
  1308. } else {
  1309. Vajda.findAllConsumables()
  1310. Vajda.createWindow()
  1311. }
  1312. }
  1313.  
  1314. Vajda.loadJobData = function(callback) {
  1315. Ajax.get('work','index', {}, function(r) {
  1316. if( r.error ) {
  1317. console.log(r.error)
  1318. return
  1319. }
  1320. JobsModel.initJobs(r.jobs)
  1321. callback()
  1322. })
  1323. }
  1324.  
  1325. Vajda.getJobSet = function(x, y, id) {
  1326. const job = Vajda.findAddedJob(x, y, id)
  1327. if ( job !== null )
  1328. return job.set
  1329. }
  1330.  
  1331. Vajda.setJobSet = function(x,y,id,set) {
  1332. const job = Vajda.findAddedJob(x, y, id)
  1333. if ( job !== null)
  1334. return job.setSet(set)
  1335. }
  1336.  
  1337. Vajda.findAddedJob = function(x, y, id) {
  1338. for ( const job of Vajda.addedJobs ) {
  1339. if ( job.x === x && job.y === y && job.id === id ) {
  1340. return job
  1341. }
  1342. }
  1343. return null
  1344. }
  1345.  
  1346. Vajda.loadSets = async function(callback) {
  1347. Ajax.remoteCallMode('inventory', 'show_equip', {}, function(r) {
  1348. Vajda.sets = r.data
  1349. if ( callback !== undefined )
  1350. callback()
  1351. })
  1352. }
  1353.  
  1354. Vajda.loadJobMotivation = function(index, callback) {
  1355. const job = Vajda.addedJobs.at(index)
  1356. Ajax.get('job', 'job', {jobId: job.id, x: job.x, y: job.y}, function(r) {
  1357. if ( callback !== undefined )
  1358. callback(r.motivation*100)
  1359. })
  1360. }
  1361.  
  1362. Vajda.loadLanguage = function() {
  1363. Ajax.remoteCall("settings", "settings", {}, function(resp) {
  1364. Vajda.language = resp.lang.account.key
  1365. })
  1366. }
  1367.  
  1368. Vajda.getConsumableIcon = function(src) {
  1369. return `<div><img src='${src}'></div>`
  1370. }
  1371.  
  1372. Vajda.getItemImage = function(id) {
  1373. return ItemManager.get(id).wear_image
  1374. }
  1375.  
  1376. Vajda.createComboxJobSets = function(x, y, id) {
  1377. let combobox = new west.gui.Combobox()
  1378. Vajda.addComboboxItems(combobox)
  1379. combobox = combobox.select(Vajda.getJobSet(x, y, id))
  1380. combobox.setWidth(60)
  1381. combobox.addListener(function(value) {
  1382. Vajda.setJobSet(x, y, id, value)
  1383. Vajda.selectTab("chosenJobs")
  1384. });
  1385. return combobox.getMainDiv()
  1386. }
  1387.  
  1388. Vajda.addComboboxItems = function(combobox) {
  1389. combobox.addItem(-1, "None")
  1390. for ( let i = 0 ; i < Vajda.sets.length; i++) {
  1391. combobox.addItem(i.toString(), Vajda.sets[i].name)
  1392. }
  1393. }
  1394.  
  1395. Vajda.updateJobDistances = function() {
  1396. for ( let i = 0; i < Vajda.allJobs.length; i++ ) {
  1397. Vajda.allJobs[i].calculateDistance()
  1398. }
  1399. }
  1400. Vajda.findJobData = function(job) {
  1401. for ( let i = 0 ;i < JobsModel.Jobs.length; i++ ) {
  1402. if ( JobsModel.Jobs[i].id === job.id ) {
  1403. return JobsModel.Jobs[i]
  1404. }
  1405. }
  1406. }
  1407.  
  1408. Vajda.findJob = function(x, y, id) {
  1409. for ( let i = 0; i < Vajda.allJobs.length; i++ ) {
  1410. if ( Vajda.allJobs[i].id === id && Vajda.allJobs[i].x === x && Vajda.allJobs[i].y === y ) {
  1411. return Vajda.allJobs[i]
  1412. }
  1413. }
  1414. }
  1415.  
  1416. Vajda.addJob = function(x, y, id) {
  1417. if ( !Vajda.checkIfJobAdded(id) ) {
  1418. Vajda.addedJobs.push(Vajda.findJob(x, y, id))
  1419. }
  1420. }
  1421.  
  1422. Vajda.removeJob = function(x, y, id) {
  1423. for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
  1424. if ( Vajda.addedJobs[i].id === id && Vajda.addedJobs[i].x === x && Vajda.addedJobs[i].y === y) {
  1425. Vajda.addedJobs.splice(i,1)
  1426. Vajda.consolidePosition(i)
  1427. break
  1428. }
  1429. }
  1430. }
  1431.  
  1432. Vajda.parseJobData = function(jobs) {
  1433. for ( let job = 0; job < jobs.length; job++ ) {
  1434. let currentJob = jobs[job]
  1435. let data = Vajda.findJobData(currentJob)
  1436. let xp = data.basis.short.experience
  1437. let money = data.basis.short.money
  1438. currentJob.setMotivation(data.jobmotivation*100)
  1439. if ( currentJob.isSilver ) {
  1440. xp = Math.ceil(1.5*xp)
  1441. money = Math.ceil(1.5*money)
  1442. }
  1443. currentJob.setExperience(xp)
  1444. currentJob.setMoney(money)
  1445. }
  1446. }
  1447.  
  1448. Vajda.getJobName = function(id) {
  1449. return JobList.getJobById(id).name
  1450. }
  1451.  
  1452. Vajda.getJobIcon = function(isSilver, id, x, y) {
  1453. return `
  1454. <div class="job" style="left: 0; top: 0; position: relative;">
  1455. <div onclick="JobWindow.open(${id}, ${x}, ${y})" class="featured ${isSilver && 'silver'}"></div>
  1456. <div class='centermap' onclick='GameMap.center(${x}, ${y})' style="position: absolute; background-image: url('../images/map/icons/instantwork.png'); width: 20px; height: 20px; top: 0; right: 3px; cursor: pointer"></div>
  1457. <img src="../images/jobs/${JobList.getJobById(id).shortname}.png" class="job_icon" alt='job_image'>
  1458. </div>
  1459. `
  1460. }
  1461.  
  1462. Vajda.checkIfJobAdded = function(id) {
  1463. for ( const job of Vajda.addedJobs ) {
  1464. if ( job.id === id ) {
  1465. return true
  1466. }
  1467. }
  1468.  
  1469. return false
  1470. }
  1471.  
  1472. Vajda.isJobSilver = function(x, y, id) {
  1473. const key = `${x}-${y}`
  1474. const jobData = GameMap.JobHandler.Featured[key]
  1475. if ( jobData === undefined || jobData[id] === undefined ) {
  1476. return false
  1477. } else {
  1478. return jobData[id].silver
  1479. }
  1480. }
  1481.  
  1482. Vajda.compareUniqueJobs = function(job, jobs){
  1483. for ( let i = 0 ; i < jobs.length; i++ ) {
  1484. if ( jobs[i].id === job.id ) {
  1485. if ( job.isSilver && !jobs[i].isSilver || (job.isSilver === jobs[i].isSilver && job.distance < jobs[i].distance) ) {
  1486. const j = jobs.at(i)
  1487. if ( !Vajda.isJobSilver(j.x, j.y, j.id) )
  1488. jobs.splice(i,1)
  1489. jobs.push(job)
  1490. }
  1491. return
  1492. }
  1493. }
  1494. jobs.push(job)
  1495. }
  1496.  
  1497. Vajda.getAllUniqueJobs = function() {
  1498. Vajda.updateJobDistances()
  1499. let jobs = []
  1500. for ( let i = 0 ; i < Vajda.allJobs.length; i++ ) {
  1501. const currentJob = Vajda.allJobs.at(i)
  1502. if ( Vajda.jobFilter.filterJob !== "" ) {
  1503. if ( !Vajda.getJobName(currentJob.id).toLowerCase().includes(Vajda.jobFilter.filterJob)) {
  1504. continue
  1505. }
  1506. }
  1507.  
  1508. if ( Vajda.checkIfJobAdded(currentJob.id) ) {
  1509. continue
  1510. }
  1511. let isSilver = Vajda.isJobSilver(currentJob.x, currentJob.y, currentJob.id)
  1512. currentJob.isSilver = isSilver
  1513. currentJob.calculateDistance()
  1514. if ( isSilver && Vajda.jobFilter.filterNoSilver ) {
  1515. continue
  1516. }
  1517.  
  1518. if ( !isSilver && Vajda.jobFilter.filterOnlySilver ) {
  1519. continue
  1520. }
  1521.  
  1522. if ( Vajda.jobFilter.filterCenterJobs && currentJob.id < 131 ) {
  1523. continue
  1524. }
  1525.  
  1526. Vajda.compareUniqueJobs(currentJob, jobs)
  1527. }
  1528.  
  1529. Vajda.parseJobData(jobs)
  1530.  
  1531. let experienceSort = function(a, b) {
  1532. if ( a === null && b === null ) {
  1533. return 0
  1534. }
  1535.  
  1536. if ( a === null && b !== null ) {
  1537. return 1
  1538. }
  1539.  
  1540. if ( a !== null && b === null ) {
  1541. return -1
  1542. }
  1543.  
  1544. let a1 = a.experience
  1545. let b1 = b.experience
  1546. return (a1 > b1) ? -1 :(a1 < b1) ? 1 :0
  1547. }
  1548.  
  1549. let reverseExperienceSort = function(a, b) {
  1550. if ( a === null && b === null ) {
  1551. return 0
  1552. }
  1553. if ( a === null && b !== null ) {
  1554. return -1
  1555. }
  1556.  
  1557. if ( a !== null && b === null ) {
  1558. return 1
  1559. }
  1560.  
  1561. let a1 = a.experience
  1562. let b1 = b.experience
  1563. return (a1 > b1) ? 1 :(a1 < b1) ? -1 :0
  1564. }
  1565.  
  1566. let distanceSort = function(a, b) {
  1567. if ( a === null && b === null ) {
  1568. return 0
  1569. }
  1570.  
  1571. if ( a === null && b !== null ) {
  1572. return 1
  1573. }
  1574.  
  1575. if ( a !== null && b === null ) {
  1576. return -1
  1577. }
  1578.  
  1579. let a1 = a.distance
  1580. let b1 = b.distance
  1581. return (a1 > b1) ? -1 :(a1 < b1) ? 1 :0
  1582. }
  1583.  
  1584. let reverseDistanceSort = function(a, b) {
  1585. if ( a === null && b === null ) {
  1586. return 0
  1587. }
  1588.  
  1589. if ( a === null && b !== null ) {
  1590. return -1
  1591. }
  1592.  
  1593. if(a !== null && b === null ) {
  1594. return 1
  1595. }
  1596.  
  1597. let a1 = a.distance
  1598. let b1 = b.distance
  1599. return (a1 > b1) ? 1 :(a1 < b1) ? -1 :0
  1600. }
  1601.  
  1602. if ( Vajda.sortJobTableXp === 1 ) {
  1603. jobs.sort(experienceSort)
  1604. }
  1605.  
  1606. if ( Vajda.sortJobTableXp === -1 ) {
  1607. jobs.sort(reverseExperienceSort)
  1608. }
  1609.  
  1610. if ( Vajda.sortJobTableDistance === 1 ) {
  1611. jobs.sort(distanceSort)
  1612. }
  1613.  
  1614. if ( Vajda.sortJobTableDistance === -1 ) {
  1615. jobs.sort(reverseDistanceSort)
  1616. }
  1617.  
  1618. return jobs
  1619. }
  1620.  
  1621. Vajda.parseStopMotivation = function() {
  1622. for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
  1623. let stopMotivation = $(".vajda-window #x-" + Vajda.addedJobs[i].x + "y-" + Vajda.addedJobs[i].y + "id-" + Vajda.addedJobs[i].id).prop("value")
  1624. if ( Vajda.isNumber(stopMotivation) ) {
  1625. Vajda.addedJobs[i].setStopMotivation(parseInt(stopMotivation))
  1626. } else {
  1627. return false
  1628. }
  1629. }
  1630. return true
  1631. }
  1632.  
  1633. Vajda.setSetForAllJobs = function() {
  1634. for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
  1635. Vajda.addedJobs[i].setSet(Vajda.jobSet)
  1636. }
  1637. }
  1638.  
  1639. Vajda.consolidePosition = function(removeIndex) {
  1640. if ( removeIndex <= Vajda.currentJob.job && Vajda.currentJob.job > 0 ) {
  1641. Vajda.currentJob.job--
  1642. }
  1643. if ( Vajda.addedJobs.length === 1 ) {
  1644. Vajda.currentJob.direction = true
  1645. }
  1646. }
  1647.  
  1648. Vajda.createDistanceMatrix = function() {
  1649. const matrix = new Array(Vajda.addedJobs.length)
  1650.  
  1651. for ( let i = 0; i < matrix.length; i++ ) {
  1652. matrix[i] = Vajda.addedJobs[i].calculateJobDistances()
  1653. }
  1654.  
  1655. return matrix
  1656. }
  1657.  
  1658. Vajda.countSetBits = function(n) {
  1659. let count = 0
  1660. while (n) {
  1661. n &= n - 1
  1662. count++
  1663. }
  1664. return count
  1665. }
  1666.  
  1667. Vajda.heldKarpSymmetric = function(distances, startJob) {
  1668. const n = distances.length
  1669. const memo = Array(1 << n).fill().map(() => Array(n).fill({ cost: Infinity, path: [] }))
  1670. memo[1 << startJob][startJob] = { cost: 0, path: [startJob] }
  1671. for ( let subsetSize = 2; subsetSize <= n; subsetSize++ ) {
  1672. for ( let subset = 0; subset < (1 << n); subset++ ) {
  1673. if ( Vajda.countSetBits(subset) === subsetSize && (subset & (1 << startJob)) ) {
  1674. for ( let end = 0; end < n; end++ ) {
  1675. if ( (subset & (1 << end)) !== 0 ) {
  1676. for ( let prevEnd = 0; prevEnd < n; prevEnd++ ) {
  1677. if ( prevEnd !== end && (subset & (1 << prevEnd)) !== 0 ) {
  1678. const newCost = memo[subset ^ (1 << end)][prevEnd].cost + distances[prevEnd][end]
  1679. if (newCost < memo[subset][end].cost) {
  1680. memo[subset][end] = { cost: newCost, path: memo[subset ^ (1 << end)][prevEnd].path.concat([end]) }
  1681. }
  1682. }
  1683. }
  1684. }
  1685. }
  1686. }
  1687. }
  1688. }
  1689. let minCost = Infinity
  1690. let minPath = []
  1691. for ( let end = 0; end < n; end++ ) {
  1692. if ( end !== startJob && memo[(1 << n) - 1][end].cost < minCost ) {
  1693. minCost = memo[(1 << n) - 1][end].cost
  1694. minPath = memo[(1 << n) - 1][end].path
  1695. }
  1696. }
  1697.  
  1698. return { cost: minCost, path: minPath }
  1699. }
  1700.  
  1701.  
  1702. Vajda.setEntryPoint = function(route) {
  1703. const firstJob = route.at(0)
  1704. const lastJob = route.at(-1)
  1705.  
  1706. if ( firstJob.calculateDistance() > lastJob.calculateDistance() )
  1707. route.reverse()
  1708.  
  1709. //i could in theory make vajda start with the job nearest to current character position but cba
  1710. }
  1711.  
  1712. Vajda.getOptimalRoute = function(distanceMatrix) {
  1713. const jobsCount = distanceMatrix.length
  1714.  
  1715. if ( jobsCount === 1 )
  1716. return {
  1717. cost: 0,
  1718. path: [0]
  1719. }
  1720.  
  1721. const routes = []
  1722. for ( let startJob = 0; startJob < jobsCount; startJob++ ) {
  1723. const { cost, path } = Vajda.heldKarpSymmetric(distanceMatrix, startJob)
  1724. routes.push({ cost, path })
  1725. }
  1726.  
  1727. return routes.reduce(function(prev, curr) {
  1728. return prev.cost < curr.cost ? prev : curr
  1729. })
  1730. }
  1731.  
  1732. Vajda.createRoute = function() {
  1733. Vajda.currentJob = {
  1734. job: 0,
  1735. direction: true
  1736. }
  1737.  
  1738. const distanceMatrix = Vajda.createDistanceMatrix()
  1739. const optimalRoute = Vajda.getOptimalRoute(distanceMatrix)
  1740.  
  1741. const addedJobsOrder = []
  1742. for ( const index of optimalRoute.path ) {
  1743. addedJobsOrder.push(Vajda.addedJobs.at(index))
  1744. }
  1745.  
  1746. Vajda.setEntryPoint(addedJobsOrder)
  1747.  
  1748. Vajda.addedJobs = addedJobsOrder
  1749. Vajda.selectTab("chosenJobs")
  1750. }
  1751.  
  1752. Vajda.createSetGui = function() {
  1753. if ( Vajda.sets.length === 0 ) {
  1754. return $(`<span style='font-size: 20px'>No sets available</span>`)
  1755. }
  1756. let htmlSkel = $(`
  1757. <div id='vajda_sets_window' style='display: block; position: relative; width: 650px; height:430px'>
  1758. <div id='vajda_sets_left' style='display: block; position: absolute; width: 250px; height: 430px; top:0px; left:0px'></div>
  1759. <div id='vajda_sets_right' style='display: block; position: absolute; width:300px; height: 410px; top: 0px; left: 325px'></div>
  1760. </div>`)
  1761. let combobox = new west.gui.Combobox("combobox_sets")
  1762. Vajda.addComboboxItems(combobox)
  1763. combobox = combobox.select(Vajda.selectedSet)
  1764. combobox.addListener(function(value) {
  1765. Vajda.selectedSet = value
  1766. Vajda.selectTab("sets")
  1767. })
  1768. let buttonSelectTravelSet = new west.gui.Button("Select travel set", function() {
  1769. Vajda.travelSet = Vajda.selectedSet
  1770. Vajda.selectTab("sets")
  1771. })
  1772. let buttonSelectJobSet = new west.gui.Button("Select job set", function() {
  1773. Vajda.jobSet = Vajda.selectedSet
  1774. Vajda.setSetForAllJobs()
  1775. Vajda.selectTab("sets")
  1776. })
  1777. let buttonSelectHealthSet = new west.gui.Button("Select health set", function() {
  1778. Vajda.healthSet = Vajda.selectedSet
  1779. Vajda.selectTab("sets")
  1780. })
  1781. let buttonSelectRegenSet = new west.gui.Button("Select regeneration set", function() {
  1782. Vajda.regenerationSet = Vajda.selectedSet
  1783. Vajda.selectTab("sets")
  1784. })
  1785. let travelSetText = "None"
  1786.  
  1787. if ( Vajda.travelSet != -1 ) {
  1788. travelSetText = Vajda.sets[Vajda.travelSet].name
  1789. }
  1790.  
  1791. let jobSetText = "None"
  1792. if ( Vajda.jobSet != -1 ) {
  1793. jobSetText = Vajda.sets[Vajda.jobSet].name
  1794. }
  1795.  
  1796. let healthSetText = "None"
  1797. if ( Vajda.healthSet != -1 ) {
  1798. healthSetText = Vajda.sets[Vajda.healthSet].name
  1799. }
  1800. let regenSetText = "None"
  1801. if ( Vajda.regenerationSet != -1 ) {
  1802. regenSetText = Vajda.sets[Vajda.regenerationSet].name
  1803. }
  1804.  
  1805. const left = $("<div></div>")
  1806. .append(
  1807. new west.gui.Groupframe()
  1808. .appendToContentPane($("<span>Sets</span><br><br>"))
  1809. .appendToContentPane(combobox.getMainDiv())
  1810. .appendToContentPane($("<br><br><span>Travel set:"+ travelSetText +"</span><br><br>"))
  1811. .appendToContentPane(buttonSelectTravelSet.getMainDiv())
  1812. .appendToContentPane($("<br><br><span>Job set:"+ jobSetText +"</span><br><br>"))
  1813. .appendToContentPane(buttonSelectJobSet.getMainDiv())
  1814. .appendToContentPane($("<br><br><span>Health set:"+ healthSetText +"</span><br><br>"))
  1815. .appendToContentPane(buttonSelectHealthSet.getMainDiv())
  1816. .getMainDiv()
  1817. )
  1818. const right = $("<div style=\'display:block; position:relative; width:300px; height:410px'\></div>")
  1819. //head div
  1820. right.append("<div class=\'wear_head wear_slot'\ style=\'display:block; position:absolute; left:30px; top:1px; width:93px; height:94px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position: -95px 0'\></div>")
  1821. //chest div
  1822. right.append("<div class=\'wear_body wear_slot'\ style=\'display:block; position:absolute; left:30px; top:106px; width:95px; height:138px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:0 0'\></div>")
  1823. //pants div
  1824. right.append("<div class=\'wear_pants wear_slot'\ style=\'display:block; position:absolute; left:30px; top:258px; width:93px; height:138px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:0 0'\></div>")
  1825. //neck div
  1826. right.append("<div class=\'wear_neck wear_slot'\ style=\'display:block; position:absolute; left:-47px; top:1px; width:74px; height:74px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:-189px 0'\></div>")
  1827. //right arm div
  1828. right.append("<div class=\'wear_right_arm wear_slot'\ style=\'display:block; position:absolute; left:-64px; top:79px; width:95px; height:138px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:0 0'\></div>")
  1829. //animal div
  1830. right.append("<div class=\'wear_animal wear_slot'\ style=\'display:block; position:absolute; left:-64px; top:223px; width:93px; height:94px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:-95px 0'\></div>")
  1831. //yield div
  1832. right.append("<div class=\'wear_yield wear_slot'\ style=\'display:block; position:absolute; left:-47px; top:321px; width:74px; height:74px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:-189px 0'\></div>")
  1833. //left arm div
  1834. right.append("<div class=\'wear_left_arm wear_slot'\ style=\'display:block; position:absolute; left:127px; top:52px; width:95px; height:138px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:0 0'\></div>")
  1835. //belt div
  1836. right.append("<div class=\'wear_belt wear_slot'\ style=\'display:block; position:absolute; left:127px; top:200px; width:93px; height:94px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:-95px 0'\></div>")
  1837. //boots div
  1838. right.append("<div class=\'wear_foot wear_slot'\ style=\'display:block; position:absolute; left:127px; top:302px; width:93px; height:94px; background:url(https://westzz.innogamescdn.com/images/window/wear/bg_sprite.png) 0 0 no-repeat; background-position:-95px 0'\></div>")
  1839. let keys = ["head","body","pants","neck","right_arm","animal","yield","left_arm","belt","foot"]
  1840. if ( Vajda.selectedSet !== -1 )
  1841. Vajda.insertSetImages(right,keys)
  1842. $("#vajda_sets_left",htmlSkel).append(left)
  1843. $("#vajda_sets_right",htmlSkel).append(right)
  1844. return htmlSkel
  1845. }
  1846.  
  1847. Vajda.getImageSkel = function() {
  1848. return $("<img src=\''\>")
  1849. }
  1850.  
  1851. Vajda.insertSetImages = function(html,keys) {
  1852. for ( let i = 0; i < keys.length; i++ ) {
  1853. if ( Vajda.sets[Vajda.selectedSet][keys[i]] !== null ) {
  1854. $(".wear_"+keys[i], html).append(Vajda.getImageSkel().attr("src", Vajda.getItemImage(Vajda.sets[Vajda.selectedSet][keys[i]])))
  1855. }
  1856. }
  1857. return html
  1858. }
  1859.  
  1860. Vajda.addEventsHeader = function() {
  1861. $(".vajda-window .jobXp").click(function() {
  1862. if ( Vajda.sortJobTableXp === 0 ) {
  1863. Vajda.sortJobTableXp = 1
  1864. } else {
  1865. ( Vajda.sortJobTableXp === 1 ) ? Vajda.sortJobTableXp = -1 : Vajda.sortJobTableXp = 1
  1866. }
  1867. Vajda.sortJobTableDistance = 0
  1868. Vajda.selectTab("jobs")
  1869. })
  1870. $(".vajda-window .jobDistance").click(function() {
  1871. if ( Vajda.sortJobTableDistance === 0 ) {
  1872. Vajda.sortJobTableDistance = 1
  1873. } else {
  1874. ( Vajda.sortJobTableDistance === 1 ) ? Vajda.sortJobTableDistance = -1 : Vajda.sortJobTableDistance = 1
  1875. }
  1876. Vajda.sortJobTableXp = 0
  1877. Vajda.selectTab("jobs")
  1878. })
  1879. }
  1880.  
  1881. Vajda.isInHomeTown = function() {
  1882. const homeTown = Character.homeTown
  1883. return GameMap.calcWayTime(Character.position,{x: homeTown.x, y: homeTown.y}) == 0
  1884. }
  1885.  
  1886. Vajda.addDeposit = async function(townId) {
  1887. const amount = Character.money
  1888. await Ajax.remoteCall("building_bank", "deposit", {
  1889. town_id: townId,
  1890. amount: amount
  1891. }, function(data) {
  1892. if (data.error == false) {
  1893. BankWindow.Balance.Mupdate(data)
  1894. Character.setDeposit(data.deposit)
  1895. Character.setMoney(data.own_money)
  1896. //new UserMessage(s(sextext('Vložil si $ %1 a zaplatil si poplatok $ %2', 'Vložila si $ %1 a zaplatila si poplatok $ %2', Character.charSex), amount, data.fee),UserMessage.TYPE_SUCCESS).show()
  1897. } else
  1898. new UserMessage(data.msg,UserMessage.TYPE_ERROR).show()
  1899. }, BankWindow)
  1900. }
  1901.  
  1902. Vajda.goDepositMoney = async function() {
  1903. const townId = Character.homeTown.town_id
  1904. if ( !townId ) return
  1905.  
  1906. await Vajda.equipSet(Vajda.travelSet)
  1907. TaskQueue.add(new TaskWalk(townId, 'town'))
  1908.  
  1909. while(true) {
  1910. if ( Vajda.isInHomeTown() ) {
  1911. break
  1912. }
  1913.  
  1914. if( !Vajda.isRunning ) {
  1915. break
  1916. }
  1917.  
  1918. await sleep(1000)
  1919. }
  1920.  
  1921. await Vajda.addDeposit(townId)
  1922. $('.tw2gui_dialog_framefix').remove()
  1923. }
  1924.  
  1925. Vajda.updateJobsMotivationOnRefill = function(val) {
  1926. return Vajda.addedJobs.map(job => job.setMotivation(p => p + val).motivation - job.stopMotivation)
  1927. }
  1928.  
  1929.  
  1930. Vajda.checkMotivation = async function(index, result, callback) {
  1931. let check = function(index, result) {
  1932. Vajda.loadJobMotivation(index, function(motivation) {
  1933. Vajda.addedJobs.at(index).setMotivation(motivation)
  1934. result.push(motivation)
  1935. if ( index + 1 < Vajda.addedJobs.length ) {
  1936. check(++index, result)
  1937. } else if( index + 1 === Vajda.addedJobs.length ) {
  1938. callback(result)
  1939. return
  1940. }
  1941. })
  1942. }
  1943. check(index, result)
  1944. }
  1945.  
  1946. Vajda.isMotivationAbove = function(result) {
  1947. for ( let i = 0; i < result.length; i++ ) {
  1948. if ( result.at(i) > Vajda.addedJobs.at(i).stopMotivation ) {
  1949. return true
  1950. }
  1951. }
  1952. return false
  1953. }
  1954.  
  1955. Vajda.isStopMotivationZero = function() {
  1956. for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
  1957. if( Vajda.addedJobs[i].stopMotivation === 0 ) {
  1958. return true
  1959. }
  1960. }
  1961. return false
  1962. }
  1963.  
  1964. Vajda.isHealthBelowLimit = function() {
  1965. if ( Vajda.settings.healthStop >= ((Character.health/Character.maxHealth) * 100) ) {
  1966. return true
  1967. }
  1968. return false
  1969. }
  1970.  
  1971. Vajda.changeJob = function() {
  1972. Vajda.currentJob.direction ? Vajda.currentJob.job++ : Vajda.currentJob.job--;
  1973. if ( Vajda.currentJob.job === Vajda.addedJobs.length ) {
  1974. Vajda.currentJob.job--
  1975. Vajda.currentJob.direction = false
  1976. } else if ( Vajda.currentJob.job < 0 ) {
  1977. Vajda.currentJob.job++
  1978. Vajda.currentJob.direction = true
  1979. }
  1980. Vajda.setCookies()
  1981. Vajda.run()
  1982. }
  1983.  
  1984. Vajda.searchBest = function(skills, jobId, onlyWearable = true) {
  1985. if (!Bag.loaded) {
  1986. EventHandler.listen('inventory_loaded', function() {
  1987. Vajda.searchBest(skills, jobId, onlyWearable)
  1988. return EventHandler.ONE_TIME_EVENT
  1989. })
  1990. return
  1991. }
  1992. let set = west.item.Calculator.getBestSet(skills, jobId), items = set && set.getItems() || [], invItems = Bag.getItemsByItemIds(items), result = [], i, invItem, wearItem
  1993. for (i = 0; i < invItems.length; i++) {
  1994. invItem = invItems[i]
  1995. wearItem = Wear.get(invItem.getType())
  1996. if (!wearItem || (wearItem && (wearItem.getItemBaseId() !== invItem.getItemBaseId() || wearItem.getItemLevel() < invItem.getItemLevel()))) {
  1997. result.push(invItem)
  1998. }
  1999. }
  2000. return result.map(item => item.obj.getId())
  2001. }
  2002.  
  2003. Vajda.getBestGear = function(jobid) {
  2004. let modelId = function(jobid) {
  2005. for ( let i = 0; i < JobsModel.Jobs.length; i++ ) {
  2006. if ( JobsModel.Jobs[i].id === jobid )
  2007. return i
  2008. }
  2009. return -1
  2010. }
  2011. const result = west.item.Calculator.getBestSet(JobsModel.Jobs[modelId(jobid)].get('skills'), jobid)
  2012. const bestItems = result && result.getItems()
  2013. return bestItems
  2014. }
  2015.  
  2016. Vajda.isWearing = function(itemId) {
  2017. if ( Wear.wear[ItemManager.get(itemId).type] === undefined) return false
  2018. return Wear.wear[ItemManager.get(itemId).type].obj.item_id == itemId
  2019. }
  2020.  
  2021. Vajda.isGearEquiped = async function(items) {
  2022. for ( const itemId of items ) {
  2023. if ( !Vajda.isWearing(itemId) ) {
  2024. return false
  2025. }
  2026. }
  2027.  
  2028. return true
  2029. }
  2030.  
  2031. Vajda.equipBestGear = async function(job) {
  2032. const bestGear = job.getBestEquipment()
  2033.  
  2034. for ( const itemId of bestGear ) {
  2035. Wear.carry(Bag.getItemByItemId(itemId))
  2036. }
  2037.  
  2038. while (true) {
  2039. const isFinished = await Vajda.isGearEquiped(bestGear)
  2040. if ( isFinished ) break
  2041. await sleep(50)
  2042. }
  2043. return Promise.resolve(true)
  2044. }
  2045.  
  2046. Vajda.getSetItemArray = function(set) {
  2047. var items = []
  2048. if ( set.head !== null )
  2049. items.push(set.head)
  2050. if ( set.neck !== null )
  2051. items.push(set.neck)
  2052. if ( set.body !== null )
  2053. items.push(set.body)
  2054. if ( set.right_arm !== null )
  2055. items.push(set.right_arm)
  2056. if ( set.left_arm !== null )
  2057. items.push(set.left_arm)
  2058. if ( set.belt !== null )
  2059. items.push(set.belt)
  2060. if ( set.foot !== null )
  2061. items.push(set.foot)
  2062. if ( set.animal !== null )
  2063. items.push(set.animal)
  2064. if ( set.yield !== null )
  2065. items.push(set.yield)
  2066. if ( set.pants !== null )
  2067. items.push(set.pants)
  2068. return items
  2069. }
  2070.  
  2071. Vajda.equipSet = async function(set) {
  2072. if ( set === -1 ) return true
  2073. EquipManager.switchEquip(Vajda.sets[set].equip_manager_id)
  2074. while ( true ) {
  2075. let isFinished = await Vajda.isGearEquiped(Vajda.getSetItemArray(Vajda.sets[set]))
  2076. if ( isFinished ) break
  2077. await sleep(50)
  2078. }
  2079. return Promise.resolve(true)
  2080. }
  2081.  
  2082. Vajda.cancelJobs = function() {
  2083. if ( TaskQueue.queue.length > 0 )
  2084. TaskQueue.cancelAll()
  2085. }
  2086.  
  2087.  
  2088. //https://prnt.sc/KAgbLNqB4zK6
  2089. Vajda.runJob = async function(jobIndex, jobCount) {
  2090. Vajda.statistics.sessionJobsCount += jobCount
  2091. Vajda.statistics.totalJobsCount += jobCount
  2092. const oldXp = Character.experience
  2093. const oldMoney = Character.money
  2094. const job = Vajda.addedJobs.at(jobIndex)
  2095. await Vajda.equipBestGear(job)
  2096. for ( let i = 0; i < jobCount; i++ ) {
  2097. JobWindow.startJob(job.id, job.x, job.y, 15)
  2098. }
  2099. Observer.start()
  2100. await sleep(Vajda.settings.setWearDelay * 1000)
  2101. Vajda.equipSet(job.set)
  2102. Manager.useBuff('character')
  2103. while (true) {
  2104. if ( TaskQueue.queue.length === 0 ) {
  2105. Vajda.updateStatistics(oldXp, oldMoney)
  2106. Vajda.setCookies()
  2107. Vajda.prepareJobRun(jobIndex)
  2108. return
  2109. }
  2110. if ( !Vajda.isRunning || Vajda.isHealthBelowLimit() ) {
  2111. break
  2112. }
  2113. await sleep(1000)
  2114. }
  2115. Vajda.statistics.sessionJobsCount -= TaskQueue.queue.length
  2116. Vajda.statistics.totalJobsCount -= TaskQueue.queue.length
  2117. Vajda.updateStatistics(oldXp, oldMoney)
  2118. Vajda.setCookies()
  2119. Vajda.cancelJobs()
  2120.  
  2121. if ( Vajda.isRunning && Vajda.isHealthBelowLimit() ) {
  2122. await sleep(2000)
  2123. Vajda.run()
  2124. }
  2125. }
  2126.  
  2127. Vajda.walkToJob = async function(index) {
  2128. const job = Vajda.addedJobs.at(index)
  2129. const jobGroup = JobList.getJobsByGroupId(job.groupId)
  2130.  
  2131. const jobToWalkTo = jobGroup.map(j =>
  2132. j.id
  2133. ).map( id => {
  2134. const j = JobsModel.getById(id)
  2135.  
  2136. return {
  2137. id: id,
  2138. workpoints: j.workpoints, //required LP
  2139. jobpoints: j.jobpoints //character has LP
  2140. }
  2141. }).reduce((prev, curr) => {
  2142. return prev.workpoints < curr.workpoints ? prev : curr
  2143. })
  2144.  
  2145. await Manager.useBuff('travel')
  2146.  
  2147. if ( Vajda.isAllowedToDepositMoney() ) {
  2148. Observer.start()
  2149. await Vajda.goDepositMoney()
  2150. }
  2151.  
  2152. JobWindow.startJob(jobToWalkTo.id, job.x, job.y, 15)
  2153. Observer.start()
  2154.  
  2155. while (true) {
  2156. if ( GameMap.calcWayTime(Character.position, {x: job.x, y: job.y} ) === 0 ) {
  2157. break
  2158. }
  2159.  
  2160. if ( !Vajda.isRunning ) {
  2161. break
  2162. }
  2163. await sleep(1000)
  2164. }
  2165. Vajda.cancelJobs()
  2166. if ( Vajda.isRunning )
  2167. Vajda.prepareJobRun(index)
  2168. }
  2169.  
  2170. Vajda.prepareJobRun = async function(index) {
  2171. const job = Vajda.addedJobs.at(index)
  2172. setTimeout(function() {
  2173. Vajda.loadJobMotivation(index, async function(motivation) {
  2174. if ( Character.energy === 0 || Vajda.isHealthBelowLimit() ) {
  2175. Vajda.run()
  2176. } else if ( motivation <= job.stopMotivation && job.stopMotivation > 0 ) {
  2177. Vajda.checkMotivation(0, [], function(result) {
  2178. if ( Vajda.isMotivationAbove(result) ) {
  2179. Vajda.changeJob()
  2180. } else {
  2181. Vajda.run()
  2182. }
  2183. })
  2184. } else if ( GameMap.calcWayTime(Character.position,{x: job.x, y: job.y}) === 0 ) {
  2185. let maxJobs = Premium.hasBonus('automation') ? 9 : 4
  2186. let numberOfJobs
  2187. if (job.stopMotivation !== 0 ) {
  2188. numberOfJobs = Math.min(Math.min(motivation - job.stopMotivation, Character.energy), maxJobs)
  2189. } else {
  2190. numberOfJobs = Math.min(Character.energy, maxJobs)
  2191. }
  2192. Vajda.runJob(index, Math.floor(numberOfJobs))
  2193. if ( Manager.isOptimized )
  2194. Manager.checkSchedule(numberOfJobs)
  2195. } else {
  2196. await Vajda.equipSet(Vajda.travelSet)
  2197. Vajda.walkToJob(index)
  2198. }
  2199. })
  2200. }, Vajda.RNG(Vajda.settings.jobDelayMin, Vajda.settings.jobDelayMax) * 1000)
  2201. }
  2202.  
  2203. Vajda.canAddMissing = function(result) {
  2204. if ( !Vajda.settings.addMotivation && Vajda.jobsBelowMotivation(result) && !Vajda.isStopMotivationZero() ) {
  2205. alert("Can't continue because of motivation")
  2206. return false
  2207. }
  2208.  
  2209. if ( !Vajda.settings.addEnergy && Character.energy === 0 ) {
  2210. alert("Can't continue because of energy")
  2211. return false
  2212. }
  2213.  
  2214. if ( !Vajda.settings.addHealth && Vajda.isHealthBelowLimit() ) {
  2215. alert("Can't continue because of health")
  2216. return false
  2217. }
  2218. return true
  2219. }
  2220.  
  2221. Vajda.finishRun = function() {
  2222. Vajda.currentState = 0
  2223. Vajda.isRunning = false
  2224. Vajda.selectTab("chosenJobs")
  2225. alert("Finished")
  2226. }
  2227.  
  2228. Vajda.jobsBelowMotivation = function(result) {
  2229. let count = 0
  2230. for ( let i = 0; i < result.length; i++ ) {
  2231. if ( result[i] <= Vajda.addedJobs[i].stopMotivation ) {
  2232. count++
  2233. }
  2234. }
  2235. return count
  2236. }
  2237.  
  2238.  
  2239.  
  2240. Vajda.averageMissingMotivation = function(result) {
  2241. let motivation = 0
  2242. for ( let i = 0; i < result.length; i++ ) {
  2243. motivation += 100-result[i]
  2244. }
  2245. return motivation/result.length
  2246. }
  2247.  
  2248.  
  2249. Vajda.fillUp = async function(result) {
  2250. const energyMissing = 100 - (Character.energy/Character.maxEnergy) * 100
  2251. const motivationMissing = Vajda.jobsBelowMotivation(result)
  2252. const averageMotivationMissing = Vajda.averageMissingMotivation(result)
  2253.  
  2254. const consumableToUse = Manager.findProperConsumable(motivationMissing, energyMissing, averageMotivationMissing)
  2255.  
  2256. if ( consumableToUse === null ) return false
  2257.  
  2258. await Manager.useConsumableOrWaitForCooldown(consumableToUse, true)
  2259.  
  2260. if ( Manager.isOptimized && consumableToUse.isCakeDecoration() ) {
  2261. const updatedMotivation = Vajda.updateJobsMotivationOnRefill(consumableToUse.motivation)
  2262. await Manager.createSchedule(updatedMotivation)
  2263. }
  2264.  
  2265. return true
  2266. }
  2267.  
  2268. Vajda.updateStatistics = function(oldXp, oldMoney) {
  2269. const xpDiff = Character.experience - oldXp
  2270. const moneyDiff = Character.money - oldMoney
  2271. Vajda.statistics.sessionXpCount += xpDiff
  2272. Vajda.statistics.totalXpCount += xpDiff
  2273.  
  2274. if ( moneyDiff > 0 ) { //spending money while vajda is running would make this a bit funky
  2275. Vajda.statistics.sessionMoneyCount += moneyDiff
  2276. Vajda.statistics.totalMoneyCount += moneyDiff
  2277. }
  2278. }
  2279.  
  2280. Vajda.run = async function() {
  2281. Vajda.checkMotivation(0, [], async function(result) {
  2282. if ( ( Vajda.isMotivationAbove(result) || Vajda.isStopMotivationZero()) && Character.energy > 0 && !Vajda.isHealthBelowLimit() ) {
  2283. Vajda.currentState = 1
  2284. Vajda.selectTab("chosenJobs")
  2285. Vajda.prepareJobRun(Vajda.currentJob.job)
  2286. } else {
  2287. if ( !Vajda.canAddMissing(result) ) {
  2288. Vajda.finishRun()
  2289. } else {
  2290. let answer = await Vajda.fillUp(result)
  2291. if ( !answer ) {
  2292. Vajda.finishRun()
  2293. }
  2294. }
  2295. }
  2296. })
  2297. }
  2298.  
  2299. Vajda.formatNumber = function(number) {
  2300. if ( typeof number === 'number' ) {
  2301. number = String(number)
  2302. }
  2303.  
  2304. const numberString = number.replace(/[ ,]/g, '')
  2305. let formattedNumber = ''
  2306. for ( let i = 0; i < numberString. length; i++ ) {
  2307. if ( i > 0 && i % 3 === 0 ) {
  2308. formattedNumber = ' ' + formattedNumber
  2309. }
  2310.  
  2311. formattedNumber = numberString[numberString.length - 1 - i] + formattedNumber
  2312. }
  2313. return formattedNumber
  2314. }
  2315.  
  2316. Vajda.createConsumablesTable = function() {
  2317. let htmlSkel = $(`<div id='consumables_overview'></div>`)
  2318. let html = $(`
  2319. <div class ='consumables_filter' style='position: relative'>
  2320. <div id='energy_consumables' style='position: absolute; top: 10px; left: 15px'></div>
  2321. <div id='motivation_consumables' style='position: absolute; top: 10px; left: 160px'></div>
  2322. <div id='health_consumables' style='position: absolute; top: 10px; left: 320px'></div>
  2323. <div id='buff_consumables' style='position: absolute; top: 10px; left: 460px'></div>
  2324. </div>`
  2325. )
  2326.  
  2327. let table = new west.gui.Table()
  2328. let consumableList = Vajda.filterConsumables(Vajda.consumableSelection.energy, Vajda.consumableSelection.motivation, Vajda.consumableSelection.health, Vajda.consumableSelection.hideBuffs)
  2329. table.addColumn("consumIcon","consumIcon").addColumn("consumCount","consumCount").addColumn("consumEnergy","consumEnergy").addColumn("consumMotivation","consumMotivation").addColumn("consumHealth","consumHealth").addColumn("consumBuffs", "consumBuffs").addColumn("consumSelected","consumSelected")
  2330. table.appendToCell("head","consumIcon","Image").appendToCell("head","consumCount","Count").appendToCell("head","consumEnergy","Energy").appendToCell("head","consumMotivation","Motivation").appendToCell("head","consumHealth","Health").appendToCell("head", "consumBuffs", "Buffs").appendToCell("head","consumSelected","Use")
  2331. for ( const consumable of consumableList ) {
  2332. const checkbox = new west.gui.Checkbox()
  2333. checkbox.setSelected(consumable.isSelected)
  2334. checkbox.setId(consumable.id)
  2335. checkbox.setCallback(function() {
  2336. Vajda.consumableTablePosition.content = $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css("top")
  2337. Vajda.consumableTablePosition.scrollbar = $(".vajda-window .tw2gui_scrollbar_pulley").css("top")
  2338. if ( consumable instanceof Buff && !consumable.hasCooldown() ) {
  2339. Manager.selectedBuffs = consumable
  2340. Vajda.selectTab('consumables')
  2341. Vajda.setCookies()
  2342. return
  2343. }
  2344. Vajda.changeConsumableSelection(parseInt(this.divMain.attr("id")), this.isSelected())
  2345. Vajda.selectTab("consumables")
  2346. Vajda.setCookies()
  2347. })
  2348. table.appendRow().appendToCell(-1,"consumIcon", Vajda.getConsumableIcon(consumable.image)).appendToCell(-1,"consumCount",consumable.count).appendToCell(-1,"consumEnergy",consumable.energy).appendToCell(-1,"consumMotivation",consumable.motivation).appendToCell(-1,"consumHealth",consumable.health).appendToCell(-1, "consumBuffs", consumable.getBuffHTML()).appendToCell(-1,"consumSelected",checkbox.getMainDiv())
  2349. }
  2350. const buttonSelect = new west.gui.Button("Select all", function() {
  2351. Vajda.changeSelectionAllConsumables(true)
  2352. Vajda.selectTab("consumables")
  2353. Vajda.setCookies()
  2354. })
  2355. const buttonDeselect = new west.gui.Button("Deselect all", function() {
  2356. Vajda.changeSelectionAllConsumables(false)
  2357. Vajda.selectTab("consumables")
  2358. Vajda.setCookies()
  2359. })
  2360. table.appendToFooter("consumEnergy",buttonSelect.getMainDiv())
  2361. table.appendToFooter("consumHealth",buttonDeselect.getMainDiv())
  2362. htmlSkel.append(table.getMainDiv())
  2363. const checkboxEnergyConsumes = new west.gui.Checkbox()
  2364. checkboxEnergyConsumes.setLabel("Energy consumables")
  2365. checkboxEnergyConsumes.setSelected(Vajda.consumableSelection.energy)
  2366. checkboxEnergyConsumes.setCallback(function() {
  2367. Vajda.consumableSelection.energy = this.isSelected()
  2368. Vajda.selectTab("consumables")
  2369. })
  2370. const checkboxMotivationConsumes = new west.gui.Checkbox()
  2371. checkboxMotivationConsumes.setLabel("Motivation consumables")
  2372. checkboxMotivationConsumes.setSelected(this.consumableSelection.motivation)
  2373. checkboxMotivationConsumes.setCallback(function() {
  2374. Vajda.consumableSelection.motivation = this.isSelected()
  2375. Vajda.selectTab("consumables")
  2376. })
  2377. const checkboxHealthConsumes = new west.gui.Checkbox()
  2378. checkboxHealthConsumes.setLabel("Health consumables")
  2379. checkboxHealthConsumes.setSelected(this.consumableSelection.health)
  2380. checkboxHealthConsumes.setCallback(function() {
  2381. Vajda.consumableSelection.health = this.isSelected()
  2382. Vajda.selectTab("consumables")
  2383. })
  2384. const buffsFilter = new west.gui.Checkbox()
  2385. buffsFilter.setLabel("Hide buffs")
  2386. buffsFilter.setSelected(this.consumableSelection.hideBuffs)
  2387. buffsFilter.setCallback(function() {
  2388. Vajda.consumableSelection.hideBuffs = this.isSelected()
  2389. Vajda.selectTab("consumables")
  2390. })
  2391. $("#energy_consumables", html).append(checkboxEnergyConsumes.getMainDiv())
  2392. $("#motivation_consumables", html).append(checkboxMotivationConsumes.getMainDiv())
  2393. $("#health_consumables", html).append(checkboxHealthConsumes.getMainDiv())
  2394. $("#buff_consumables", html).append(buffsFilter.getMainDiv())
  2395. htmlSkel.append(html)
  2396. return htmlSkel
  2397. }
  2398.  
  2399. Vajda.createAddedJobsTab = function() {
  2400. const htmlSkel = $(`<div id='added_jobs_overview'></div>`)
  2401. const footerHtml = $(`
  2402. <div id='start_vajda' style='position: relative'>
  2403. <span id='vajda-state-info' class='vajda_state' style='position: absolute; left: 20px; top: 10px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-weight: bold;'>
  2404. Current state: ${Vajda.states[Vajda.currentState]}
  2405. </span>
  2406. <div class='vajda_run' style='position: absolute; left: 350px; top: 20px'></div>
  2407. </div>
  2408. `)
  2409. const table = new west.gui.Table()
  2410. table.addColumn("jobIcon","jobIcon").addColumn("jobName","jobName").addColumn("jobStopMotivation","jobStopMotivation").addColumn("jobSet","jobSet").addColumn("jobRemove","jobRemove")
  2411. table.appendToCell("head","jobIcon","Job icon").appendToCell("head","jobName","Job name").appendToCell("head","jobStopMotivation","Stop motivation").appendToCell("head","jobSet","Job set").appendToCell("head","jobRemove","")
  2412. for ( let job = 0; job < Vajda.addedJobs.length; job++ ) {
  2413. table.appendRow().appendToCell(-1,"jobIcon", Vajda.getJobIcon(Vajda.addedJobs[job].isSilver, Vajda.addedJobs[job].id, Vajda.addedJobs[job].x, Vajda.addedJobs[job].y)).appendToCell(-1,"jobName", Vajda.getJobName(Vajda.addedJobs[job].id)).appendToCell(-1,"jobStopMotivation", Vajda.createMinMotivationTextfield(Vajda.addedJobs[job].x, Vajda.addedJobs[job].y, Vajda.addedJobs[job].id, Vajda.addedJobs[job].stopMotivation)).appendToCell(-1,"jobSet", Vajda.createComboxJobSets(Vajda.addedJobs[job].x, Vajda.addedJobs[job].y, Vajda.addedJobs[job].id)).appendToCell(-1,"jobRemove", Vajda.createRemoveJobButton(Vajda.addedJobs[job].x, Vajda.addedJobs[job].y, Vajda.addedJobs[job].id))
  2414. }
  2415. const buttonStart = new west.gui.Button("Start", async function() {
  2416. const parseSuccesful = Vajda.parseStopMotivation()
  2417. if ( parseSuccesful ) {
  2418. Vajda.currentState = 3
  2419. $(`#vajda-state-info`).text(`Current state: ${Vajda.states[3]}`)
  2420. Vajda.createRoute()
  2421. Vajda.isRunning = true
  2422. Vajda.setCookies()
  2423. if ( Manager.isOptimized && Manager.hasEnoughPlugsAndDecorations() ) {
  2424. await Manager.createSchedule()
  2425. }
  2426. Observer.start()
  2427. Vajda.run()
  2428. } else {
  2429. new UserMessage("Wrong format of set stop motivation", UserMessage.TYPE_ERROR).show()
  2430. }
  2431. });
  2432. const buttonStop = new west.gui.Button("Stop",function() {
  2433. Vajda.isRunning = false
  2434. Vajda.currentState = 0
  2435. Vajda.selectTab("chosenJobs")
  2436. Observer.stop()
  2437. })
  2438. htmlSkel.append(table.getMainDiv())
  2439. $(".vajda_run",footerHtml).append(buttonStart.getMainDiv())
  2440. $(".vajda_run",footerHtml).append(buttonStop.getMainDiv())
  2441. htmlSkel.append(footerHtml)
  2442. return htmlSkel
  2443. }
  2444.  
  2445.  
  2446. Vajda.createStatisticsGui = function() {
  2447. const offsetLeft = '.5rem'
  2448.  
  2449. const statsBubbleStyle = `'
  2450. padding: 1rem 2rem;
  2451. border-radius: 10px;
  2452. background-color: rgba(255, 255, 228, .3);
  2453. position: relative;
  2454. box-shadow: 0 0 5px rgba(0, 0, 0, .2)
  2455. '`
  2456.  
  2457. const pseudoHeadingStyle = `'
  2458. display: block;
  2459. width: calc(100% - ${offsetLeft});
  2460. padding-left: ${offsetLeft};
  2461. border-bottom: 1px solid black;
  2462. margin-bottom: .5rem
  2463. '`
  2464.  
  2465. const refreshStats = `
  2466. <div style=${statsBubbleStyle}>
  2467. <b style=${pseudoHeadingStyle}>REFRESH COUNT</b>
  2468. <p style='padding-left:${offsetLeft}'>Total in this session: ${Observer.refreshCount}</p>
  2469. </div>
  2470. `
  2471.  
  2472. return $(`
  2473. <div id='statistics_overview' style='padding: 0 2rem; display: grid; gap: 1rem'>
  2474. <div style=${statsBubbleStyle}>
  2475. <b style=${pseudoHeadingStyle}>EXPERIENCE</b>
  2476. <p style='padding-left: ${offsetLeft}'>Total in this session: ${Vajda.formatNumber(Vajda.statistics.sessionXpCount)}</p>
  2477. <p style='padding-left: ${offsetLeft}'>Total overall: ${Vajda.formatNumber(Vajda.statistics.totalXpCount)}</p>
  2478. </div>
  2479.  
  2480. <div style=${statsBubbleStyle}>
  2481. <b style=${pseudoHeadingStyle}>MONEY</b>
  2482. <p style='padding-left: ${offsetLeft}'>Total in this session: ${Vajda.formatNumber(Vajda.statistics.sessionMoneyCount)}</p>
  2483. <p style='padding-left: ${offsetLeft}'>Total overall: ${Vajda.formatNumber(Vajda.statistics.totalMoneyCount)}</p>
  2484. </div>
  2485.  
  2486. <div style=${statsBubbleStyle}>
  2487. <b style=${pseudoHeadingStyle}>JOBS</b>
  2488. <p style='padding-left: ${offsetLeft}'>Total in this session: ${Vajda.formatNumber(Vajda.statistics.sessionJobsCount)}</p>
  2489. <p style='padding-left: ${offsetLeft}'>Total overall: ${Vajda.formatNumber(Vajda.statistics.totalJobsCount)}</p>
  2490. </div>
  2491.  
  2492. ${Observer.isEnabled ? refreshStats : ''}
  2493. </div>
  2494. `)
  2495. }
  2496.  
  2497. Vajda.createSettingsGui = function() {
  2498. const htmlSkel = $(`<div id='settings_overview' style='padding: 10px'></div>`)
  2499. const checkboxAddEnergy = new west.gui.Checkbox()
  2500. checkboxAddEnergy.setLabel("Add energy")
  2501. checkboxAddEnergy.setSelected(Vajda.settings.addEnergy)
  2502. checkboxAddEnergy.setCallback(function() {
  2503. Vajda.settings.addEnergy = !Vajda.settings.addEnergy
  2504. })
  2505. const checkboxAddMotivation = new west.gui.Checkbox()
  2506. checkboxAddMotivation.setLabel("Add motivation")
  2507. checkboxAddMotivation.setSelected(Vajda.settings.addMotivation)
  2508. checkboxAddMotivation.setCallback(function() {
  2509. Vajda.settings.addMotivation = !Vajda.settings.addMotivation
  2510. })
  2511. const checkboxAddHealth = new west.gui.Checkbox()
  2512. checkboxAddHealth.setLabel("Add health")
  2513. checkboxAddHealth.setSelected(Vajda.settings.addHealth)
  2514. checkboxAddHealth.setCallback(function() {
  2515. Vajda.settings.addHealth = !Vajda.settings.addHealth
  2516. })
  2517.  
  2518. const buttPlugsCheckbox = new west.gui.Checkbox()
  2519. buttPlugsCheckbox.setLabel('Optimize for butt plugs and cake decorations')
  2520. buttPlugsCheckbox.setSelected(Manager.isOptimized)
  2521. buttPlugsCheckbox.setCallback(() => {
  2522. Manager.isOptimized = p => !p
  2523. })
  2524.  
  2525. const enableObserverCheckbox = new west.gui.Checkbox()
  2526. enableObserverCheckbox.setLabel('[Experimental] Enable auto refresh → Read user manual')
  2527. enableObserverCheckbox.setSelected(Observer.isEnabled)
  2528. enableObserverCheckbox.setCallback(() => {
  2529. Observer.isEnabled = previous => {
  2530. $('#observer-delay-input').css('max-height', previous ? '0px' : '30px')
  2531. Vajda.isRunning && !previous && Observer.start(forceStart = true)
  2532. Vajda.isRunning && previous && Observer.stop()
  2533.  
  2534. return !previous
  2535. }
  2536. })
  2537.  
  2538. const observerDelayInput = new west.gui.Textfield()
  2539. observerDelayInput.setWidth(100)
  2540. observerDelayInput.setValue(Observer.getTimeOut(true))
  2541. observerDelayInput.getMainDiv()[0].querySelector('input').addEventListener('change', e => {
  2542. const val = e.target.value
  2543.  
  2544. if ( Vajda.isNumber(val) ) {
  2545. Observer.timeOut = val
  2546. }
  2547. })
  2548.  
  2549. const style = (isOpen) => `'
  2550. overflow: hidden;
  2551. max-height: ${isOpen ? '30' : '0'}px;
  2552. transition: max-height .5s;
  2553. margin-bottom: 1rem;
  2554. '`
  2555. const observerDelay = $(`
  2556. <div style=${style(Observer.isEnabled)} id='observer-delay-input'>
  2557. Refresh page after
  2558. </div>
  2559. `)
  2560. observerDelay.append(observerDelayInput.getMainDiv())
  2561. observerDelay.append(` minutes since the last action`)
  2562.  
  2563. const saveMoneyCheckbox = new west.gui.Checkbox()
  2564. saveMoneyCheckbox.setLabel('Deposit money in your hometown')
  2565. saveMoneyCheckbox.setSelected(Vajda.settings.addDeposit.isEnabled)
  2566. saveMoneyCheckbox.setCallback(() => {
  2567. if ( Character.homeTown.town_id === 0 ) {
  2568. new UserMessage("You don' have a home town", UserMessage.TYPE_HINT).show()
  2569. return
  2570. }
  2571.  
  2572. const oldVal = !!Vajda.settings.addDeposit.isEnabled
  2573. Vajda.settings.addDeposit.isEnabled = !oldVal
  2574.  
  2575. $(`#deposit-limit-input`).css('max-height', oldVal ? '0px' : '30px')
  2576. })
  2577.  
  2578. const depositLimit = $(`
  2579. <div style=${style(Vajda.settings.addDeposit.isEnabled)} id='deposit-limit-input'>
  2580. Deposit when more than
  2581. </div>
  2582. `)
  2583.  
  2584. const limitInput = new west.gui.Textfield()
  2585. limitInput.setWidth(100)
  2586. limitInput.setValue(Number.isNaN(Vajda.settings.addDeposit.limit) ? '' : Vajda.settings.addDeposit.limit)
  2587. limitInput.getMainDiv()[0].querySelector('input').addEventListener('change', e => {
  2588. const val = e.target.value
  2589.  
  2590. if ( Vajda.isNumber(val) ) {
  2591. Vajda.settings.addDeposit.limit = val
  2592. }
  2593. })
  2594.  
  2595. depositLimit.append(limitInput.getMainDiv())
  2596. depositLimit.append(` $ in cash`)
  2597.  
  2598.  
  2599. const htmlHealthStop = $("<div></div>")
  2600. htmlHealthStop.append(`<span>Stoppage health percent value</span>`)
  2601. const healthStopTextfiled = new west.gui.Textfield("healthStop")
  2602. healthStopTextfiled.setValue(Vajda.settings.healthStop)
  2603. healthStopTextfiled.setWidth(100)
  2604. htmlHealthStop.append(healthStopTextfiled.getMainDiv())
  2605. const htmlSetWearDelay = $("<div></div>")
  2606. htmlSetWearDelay.append("<span> Job set equip delay </span>")
  2607. const setWearDelayTextfiled = new west.gui.Textfield("setWearDelay")
  2608. setWearDelayTextfiled.setValue(Vajda.settings.setWearDelay)
  2609. setWearDelayTextfiled.setWidth(100)
  2610. htmlSetWearDelay.append(setWearDelayTextfiled.getMainDiv())
  2611.  
  2612. const htmlJobDelay = $("<div></div>")
  2613. htmlJobDelay.append(`<span>Random delay between jobs(seconds)</span>`)
  2614. const jobDelayTextFieldMin = new west.gui.Textfield("jobDelay")
  2615. jobDelayTextFieldMin.setValue(Vajda.settings.jobDelayMin)
  2616. jobDelayTextFieldMin.setWidth(50)
  2617. const jobDelayTextFieldMax = new west.gui.Textfield("jobDelay")
  2618. jobDelayTextFieldMax.setValue(Vajda.settings.jobDelayMax)
  2619. jobDelayTextFieldMax.setWidth(50)
  2620.  
  2621. htmlJobDelay.append(jobDelayTextFieldMin.getMainDiv())
  2622. htmlJobDelay.append("<span> - </span>")
  2623. htmlJobDelay.append(jobDelayTextFieldMax.getMainDiv())
  2624.  
  2625.  
  2626. const manualLink = `
  2627. <div onclick=Vajda.selectTab('manual') style="cursor: pointer; text-decoration: underline; position: absolute; top: 20px; right: 25px;">
  2628. Open User Manual <svg style="width: 10px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M352 0c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9L370.7 96 201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L416 141.3l41.4 41.4c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6V32c0-17.7-14.3-32-32-32H352zM80 32C35.8 32 0 67.8 0 112V432c0 44.2 35.8 80 80 80H400c44.2 0 80-35.8 80-80V320c0-17.7-14.3-32-32-32s-32 14.3-32 32V432c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H192c17.7 0 32-14.3 32-32s-14.3-32-32-32H80z"/></svg>
  2629. </div>
  2630. `
  2631.  
  2632. const buttonApply = new west.gui.Button("Apply", function() {
  2633. Vajda.settings.addEnergy = checkboxAddEnergy.isSelected()
  2634. Vajda.settings.addMotivation = checkboxAddMotivation.isSelected()
  2635. Vajda.settings.addHealth = checkboxAddHealth.isSelected()
  2636. if ( Vajda.isNumber(healthStopTextfiled.getValue()) ) {
  2637. let healthStop = parseInt(healthStopTextfiled.getValue())
  2638. healthStop = Math.min(30,healthStop)
  2639. Vajda.settings.healthStop = healthStop
  2640. }
  2641.  
  2642. if ( Vajda.isNumber(setWearDelayTextfiled.getValue()) ) {
  2643. let setWearDelay = parseInt(setWearDelayTextfiled.getValue())
  2644. setWearDelay = Math.min(10,setWearDelay)
  2645. Vajda.settings.setWearDelay = setWearDelay
  2646. }
  2647.  
  2648. if ( Vajda.isNumber(jobDelayTextFieldMin.getValue()) ) {
  2649. let jobDelayTimeMin = parseInt(jobDelayTextFieldMin.getValue())
  2650. Vajda.settings.jobDelayMin = jobDelayTimeMin
  2651. } else {
  2652. Vajda.settings.jobDelayMin = 0
  2653. Vajda.settings.jobDelayMax = 0
  2654. new UserMessage("Wrong format of delay job min value. Please set a number.", UserMessage.TYPE_ERROR).show()
  2655. }
  2656.  
  2657. if ( Vajda.isNumber(jobDelayTextFieldMax.getValue()) ) {
  2658. let jobDelayTimeMax = parseInt(jobDelayTextFieldMax.getValue())
  2659. Vajda.settings.jobDelayMax = jobDelayTimeMax
  2660. } else {
  2661. Vajda.settings.jobDelayMin = 0
  2662. Vajda.settings.jobDelayMax = 0
  2663. new UserMessage("Wrong format of delay job max value. Please set a number.", UserMessage.TYPE_ERROR).show()
  2664. }
  2665. Vajda.setCookies()
  2666. Vajda.selectTab("settings")
  2667. })
  2668.  
  2669. htmlSkel.append(manualLink)
  2670.  
  2671. htmlSkel.append(checkboxAddEnergy.getMainDiv())
  2672. htmlSkel.append("<br>")
  2673. htmlSkel.append(checkboxAddMotivation.getMainDiv())
  2674. htmlSkel.append("<br>")
  2675. htmlSkel.append(checkboxAddHealth.getMainDiv())
  2676. htmlSkel.append("<br>")
  2677. htmlSkel.append(buttPlugsCheckbox.getMainDiv())
  2678. htmlSkel.append("<br>")
  2679. htmlSkel.append(enableObserverCheckbox.getMainDiv())
  2680. htmlSkel.append("<br>")
  2681. htmlSkel.append(observerDelay)
  2682. htmlSkel.append(saveMoneyCheckbox.getMainDiv())
  2683. htmlSkel.append(depositLimit)
  2684. htmlSkel.append(htmlHealthStop)
  2685. htmlSkel.append("<br>")
  2686. htmlSkel.append(htmlSetWearDelay)
  2687. htmlSkel.append("<br>")
  2688. htmlSkel.append(htmlJobDelay)
  2689. htmlSkel.append("<br>")
  2690. htmlSkel.append(buttonApply.getMainDiv())
  2691. return htmlSkel
  2692. }
  2693.  
  2694. Vajda.createManualGui = function() {
  2695. const listStyle = `'padding-inline-start: 14px'`
  2696. const nestedListStyle = `'padding-inline-start: 30px'`
  2697. const containerStyle = `'
  2698. padding: 0 30px 30px
  2699. '`
  2700.  
  2701. const html = `
  2702. <div style=${containerStyle}>
  2703. <h3>Read Before use</h3>
  2704. <ol style=${listStyle}>
  2705. <li>
  2706. <strong>Calculating optimal route</strong> takes time and memory, a lot of it. It might not be noticeable for up to 12-14 jobs,
  2707. but anything more than that... you will notice a short freeze of the window. I don't recommend selecting more than 18 jobs, as the
  2708. algorithm will take about a minute (depending on the hardware, of course) to execute, while it takes almost 8 minutes to
  2709. find the best route for 20 jobs. In these scenarios, your browser may appear unresponsive and prompt you to reload the page
  2710. or wait. I recommend being patient and allowing some time for the algorithm to complete. If that doesn't work, remove one
  2711. or two jobs; that's the cheapest way to solve this problem.
  2712. </li>
  2713.  
  2714. <li>
  2715. <strong>The optimization for butt plugs and cake decorations</strong> setting, which is most likely why you are here:
  2716. <ul style=${nestedListStyle}>
  2717. <li>The setting has to be enabled <i>before</i> you start Zdenka, it won't work otherwise</li>
  2718. <li>The <i>Add motivation</i> setting has to be enabled as well</li>
  2719. <li>Do not start Zdenka with low energy and consumables on cooldown</li>
  2720. <li>Do not use consumables yourself while it's running</li>
  2721. <li>
  2722. You don't have to select consumables manually with this setting, Zdenka will do it for you. Just make sure
  2723. you have enough of them butt plugs and decorations
  2724. </li>
  2725. </ul>
  2726.  
  2727. These restrictions are simply the cost of having Zdenka refill energy <i>while</i> doing jobs.
  2728. </li>
  2729.  
  2730. <li>
  2731. Zdenka can <strong>travel</strong> to jobs that you can't do in travel set (unless you are super low level).
  2732. </li>
  2733.  
  2734. <li>
  2735. <strong>Buffs</strong> will be used automatically when selected (and when no buff is active, of course). Only one buff
  2736. of each type can be selected at once. Keep in mind that consumables with cooldown are <b>not</b> treated as buffs and will
  2737. only be used to refill whatever your character needs.
  2738. </li>
  2739.  
  2740. <li>
  2741. Zdenka will display <strong>all silver jobs</strong>, not just those you can do and are closest to yoor character. This
  2742. allows you <i>some</i> control of the route, for instance there might be multiple silver jobs of the same kind and one
  2743. of them might simply be in a more advantageous position.
  2744. </li>
  2745.  
  2746. <li>
  2747. When <strong>Auto Refresh</strong> is enabled, Zdenka will refresh the page and start automatically <i>n</i> minutes
  2748. after starting a job (or walking to one). Starting new jobs will restart this countdown. Do not set the delay to low numbers,
  2749. Zdenka enforces a minimum of 2.5 minutes anyway, however, I do recommend a slightly longer delay.
  2750. </li>
  2751. </ol>
  2752. </div>
  2753. `
  2754.  
  2755. const container = new west.gui.Scrollpane().getMainDiv()
  2756. container.style = 'height: 400px; overflow-y: scroll'
  2757. container.innerHTML = html
  2758.  
  2759.  
  2760. return container
  2761. }
  2762.  
  2763. Vajda.createMenuIcon = function() {
  2764. const menuImage = 'data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAAHdElNRQfoAwISKiXgp+5lAAAFKUlEQVRIx4WVy28cWRXGf+dWudvtdrc78TOjJJOHIUOiZDGLGbFAQUKDYMWfwGKGBRIrHmLBgoeGBRI7/gxACGmkEQiQYEZkCBNmnJB4jOPYcWx30u9HdXVVddU9LLr65Qhxpaq6p+rc853vfLfOlQ/vbqsxgjEGJ72MMTiOQUTGlzHTts7YxgjGmfg6jsGYqW8iTJyngo7GyFa1WBsDishsAiP3/2W78DLANHA8CDn6zz28epm18+fI5ZfIn7nAQnE1DQRiJokZI1MAw6crAgJjkJnsgedP7lP++A+4SUJ/UMcun6Vb22f9ypsUVi6C6DBAum56PQgCuIbTLCaOfa/N4f07nD9T4NLVTVDweh0afovKwT/JFZbJ5PII0+t4aW7kFMDESehWj3hxsEsQK5VGGysO7W5I7WmZ2tM9/NbRKf2YmY9MM/1hmrKi9DpVwiDk37snPNh+itdusP2kzO6TFxw93qdTeYZNEv7fMKczGdsKg7CP6whv3LjKGzc/h9rh/Pbr13AFWuXHxKHHJOfJUJ3M3dNbdoIIySAimxU06GK9ObqVDu6Cg9fvMJfL4nt1wm6VbL6EqqKaVkF1JqaZ3m4zlFRRG+InMUf1Fkmzy1Kti+kF1Hp9EjEMogi/U8PaZBxcpyioDt+ZmdRTR2xCMuiTyw5YW8lTqVY48dqEmxsc97t8uv0Y11FElaB1TNRrjbUZBVZVlOFzRhPVIVavXaZx8BGxV4EkZmV5CTeT5dH9BxwfP6ewtEDpTIFCYZFBp0z7ZIdEbRp8CkRBX9JEgDAi8/AzGtt/4oVtU280+fz5K1y6usm5V16h1aqze7zHfDZHoVike3BI6RDcM1fQ9Y2xNtNA7oxIfh/3V7+k9LvfUHQTovVF9FyJ1QubzGfnWSwWyQDB82cMtj6l3gjJ3d9j/aDCwh//jP+Td7HXb55iI8i9rT0VEcR1MXc+pPSddyj0fRwgEqG7kCW4uMb8pQsUvQTb6dIddAm7HsVnDfLAHBABXP8C0U/fJb79FYwIjjPs3mZaEHP3Dk7fRxAcgRzKai9gdecIHjwiONiFw30kDDhX7bIMZAUsQojQf7SN/OD7mI/vYh0Hq2CtTUFEwPeZ2/oXAsQiKIIzFI28tayftMgEMVE+x1K5zXwwGCaT/hs9gZYIrYN99Ec/ZO7997CdLlbBqCqIIPUacniAAj6QpD1UZNi+HYWlapvVozqLfjjuTQ6QCJRVaaqSiBB98gnxt97G/uzH2HZ7wsS0mphuBxA8oD3sLMNjQGX01w4TmmrjCnhiGHzxS8Sv3cAAAxFafo/mr39L+MEHuCMQp9MmE0WYlIWHsILi2CGQIFh00qUEVCBQxXv1Ihs//wVJPyD49jtw+IQI6K2VaFb3UiZRhPz1LzhhiIgwlzLopaULUCIUmyYQAYGCp3AMlC9dRtfWca9dI/nm27TyBZqrywTf+DLNuI2L4yAPH5K8/x4+MI8yQFAUD5gXIatKBkVT1oMUyEc4UYVCCTXO8BT82lsEtceYrJJsrFDthLgqguzvYRpVQqCvUBMoMSrTzG10CqAIMRACa4Uiqoq3/xm9nX+Q3VylHcYEmbNc/+ptXBKLXr5M762vEz64R7/n04oGnI2icdAk1cOkAAkyLtsc4DhKc+tvBCc7hKFPn3kWXn2d1269ycJiEVesRW/cwv/u9wg++j3hcYXk71s42ztYwKYcIgQzLBgJkKDECBnX5bB1jP/wDswtULx8i4tXbrK4soEYQxzH/BeqMKTC7KpG/gAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNC0wMy0wMlQxODo0MjozMSswMDowMC8Ty8sAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjQtMDMtMDJUMTg6NDI6MzErMDA6MDBeTnN3AAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0LTAzLTAyVDE4OjQyOjM3KzAwOjAwaotnkgAAAABJRU5ErkJggg=='
  2765. let div = $('<div class="ui_menucontainer" />')
  2766. let link = $('<div id="vajda_menu" class="menulink" onclick=Vajda.loadJobs() title="Zdenka Studenková" />').css('background-image', 'url(' + menuImage + ')')
  2767. $('#ui_menubar').append((div).append(link).append('<div class="menucontainer_bottom" />'))
  2768. }
  2769.  
  2770.  
  2771. Vajda.createWindow = function(isHumanAction = true) {
  2772. const window = wman.open("vajda").setResizeable(false).setMinSize(650, 480).setSize(650, 480).setMiniTitle("Vajda Jožo")
  2773. const tabs = {
  2774. "jobs": "Jobs",
  2775. "chosenJobs": "Chosen Jobs",
  2776. "sets": "Sets",
  2777. "consumables": "Consumables",
  2778. "stats": "Statistics",
  2779. "settings": "Settings",
  2780. "manual": "User manual"
  2781. }
  2782.  
  2783. let tabLogic = function(win,id) {
  2784. const content = $(`<div class='vajda-window'></div>`)
  2785. switch(id) {
  2786. case 'jobs':
  2787. Vajda.loadJobData(function(){
  2788. Vajda.removeActiveTab(this)
  2789. Vajda.removeWindowContent()
  2790. Vajda.addActiveTab("jobs",this)
  2791. content.append(Vajda.createJobsTab())
  2792. Vajda.window.appendToContentPane(content)
  2793. Vajda.addJobTableCss()
  2794. $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css({"top": Vajda.jobTablePosition.content})
  2795. $(".vajda-window .tw2gui_scrollbar_pulley").css({"top": Vajda.jobTablePosition.scrollbar})
  2796. Vajda.addEventsHeader()
  2797. })
  2798. break
  2799. case 'chosenJobs':
  2800. Vajda.removeActiveTab(this)
  2801. Vajda.removeWindowContent()
  2802. Vajda.addActiveTab("chosenJobs", this)
  2803. content.append(Vajda.createAddedJobsTab())
  2804. Vajda.window.appendToContentPane(content)
  2805. $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css({"top": Vajda.addedJobTablePosition.content})
  2806. $(".vajda-window .tw2gui_scrollbar_pulley").css({"top": Vajda.addedJobTablePosition.scrollbar})
  2807. Vajda.addAddedJobsTableCss()
  2808. break
  2809. case 'sets':
  2810. Vajda.loadSets(function() {
  2811. Vajda.removeActiveTab(this)
  2812. Vajda.removeWindowContent()
  2813. Vajda.addActiveTab("sets",this)
  2814. content.append(Vajda.createSetGui())
  2815. Vajda.window.appendToContentPane(content)
  2816. })
  2817. break
  2818. case 'consumables':
  2819. Vajda.removeActiveTab(this)
  2820. Vajda.removeWindowContent()
  2821. Vajda.addActiveTab("consumables",this)
  2822. Vajda.findAllConsumables()
  2823. content.append(Vajda.createConsumablesTable())
  2824. Vajda.window.appendToContentPane(content)
  2825. $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css({"top": Vajda.consumableTablePosition.content})
  2826. $(".vajda-window .tw2gui_scrollbar_pulley").css({"top": Vajda.consumableTablePosition.scrollbar})
  2827. Vajda.addConsumableTableCss()
  2828. break
  2829. case 'stats':
  2830. Vajda.removeActiveTab(this)
  2831. Vajda.removeWindowContent()
  2832. Vajda.addActiveTab("stats",this)
  2833. content.append(Vajda.createStatisticsGui())
  2834. Vajda.window.appendToContentPane(content)
  2835. break
  2836. case 'settings':
  2837. Vajda.removeActiveTab(this)
  2838. Vajda.removeWindowContent()
  2839. Vajda.addActiveTab("settings",this)
  2840. content.append(Vajda.createSettingsGui())
  2841. Vajda.window.appendToContentPane(content)
  2842. break
  2843. case 'manual':
  2844. Vajda.removeActiveTab(this)
  2845. Vajda.removeWindowContent()
  2846. Vajda.addActiveTab("manual", this)
  2847. content.append(Vajda.createManualGui())
  2848. Vajda.window.appendToContentPane(content)
  2849. break
  2850. }
  2851. }
  2852.  
  2853. for(let tab in tabs) {
  2854. window.addTab(tabs[tab],tab,tabLogic)
  2855. }
  2856.  
  2857. Vajda.window = window
  2858.  
  2859. if ( !isHumanAction ) wman.close('vajda')
  2860.  
  2861. Vajda.selectTab('jobs')
  2862. }
  2863.  
  2864. Vajda.selectTab = function(key) {
  2865. Vajda.window.tabIds[key].f(Vajda.window,key)
  2866. }
  2867.  
  2868. Vajda.removeActiveTab = function(window) {
  2869. $('div.tw2gui_window_tab', window.divMain).removeClass('tw2gui_window_tab_active')
  2870. }
  2871.  
  2872. Vajda.addActiveTab = function(key, window) {
  2873. $(`div._tab_id_${key}`, window.divMain).addClass('tw2gui_window_tab_active')
  2874. }
  2875. Vajda.removeWindowContent = function() {
  2876. $(".vajda-window").remove()
  2877. }
  2878.  
  2879. Vajda.addConsumableTableCss = function() {
  2880. $(".vajda-window .consumIcon").css({"width":"80px"})
  2881. $(".vajda-window .consumCount").css({"width":"60px"})
  2882. $(".vajda-window .consumEnergy").css({"width":"60px"})
  2883. $(".vajda-window .consumMotivation").css({"width":"70px"})
  2884. $(".vajda-window .consumHealth").css({"width":"60px"})
  2885. $(".vajda-window .consumBuffs").css({"width": "150px"})
  2886. $(".vajda-window .row").css({"height":"80px"})
  2887. $('.vajda-window').find('.tw2gui_scrollpane').css('height', '250px')
  2888. }
  2889.  
  2890. Vajda.addJobTableCss = function() {
  2891. $(".vajda-window .jobIcon").css({"width":"80px"})
  2892. $(".vajda-window .jobName").css({"width":"150px"})
  2893. $(".vajda-window .jobXp").css({"width":"40px"})
  2894. $(".vajda-window .jobMoney").css({"width":"40px"})
  2895. $(".vajda-window .jobMotivation").css({"width":"40px"})
  2896. $(".vajda-window .jobDistance").css({"width":"100px"})
  2897. $(".vajda-window .row").css({"height":"60px"})
  2898. $('.vajda-window').find('.tw2gui_scrollpane').css('height', '250px')
  2899. }
  2900.  
  2901. Vajda.addAddedJobsTableCss = function() {
  2902. $(".vajda-window .jobIcon").css({"width":"80px"})
  2903. $(".vajda-window .jobName").css({"width":"130px"})
  2904. $(".vajda-window .jobStopMotivation").css({"width":"110px"})
  2905. $(".vajda-window .jobRemove").css({"width":"105px"})
  2906. $(".vajda-window .jobSet").css({"width":"100px"})
  2907. $(".vajda-window .row").css({"height":"60px"})
  2908. $('.vajda-window').find('.tw2gui_scrollpane').css('height', '250px')
  2909. }
  2910.  
  2911. Vajda.createJobsTab = function() {
  2912. const htmlSkel = $(`<div id='jobs_overview'></div>`)
  2913. const html = $(`
  2914. <div class='jobs_search' style='position: relative'>
  2915. <div id='jobFilter' style='position: absolute; top: 10px; left: 15px'></div>
  2916. <div id='job_only_silver' style='position: absolute; top:10px; left: 200px;'></div>
  2917. <div id='job_no_silver' style='position: absolute; top: 10px; left: 270px;'></div>
  2918. <div id='job_center' style='position: absolute; top: 10px; left: 350px;'></div>
  2919. <div id='button_filter_jobs' style='position: absolute; top: 5px; left: 450px;'></div>
  2920. </div>
  2921. `)
  2922. const table = new west.gui.Table()
  2923. const xpIcon = '<img src="/images/icons/star.png">'
  2924. const dollarIcon = '<img src="/images/icons/dollar.png">'
  2925. const motivationIcon = '<img src="/images/icons/motivation.png">'
  2926. const arrow_desc = '&nbsp;<img src="../images/window/jobs/sortarrow_desc.png"/>'
  2927. const arrow_asc = '&nbsp;<img src="../images/window/jobs/sortarrow_asc.png"/>'
  2928. const uniqueJobs = Vajda.getAllUniqueJobs()
  2929. table
  2930. .addColumn("jobIcon","jobIcon")
  2931. .addColumn("jobName","jobName")
  2932. .addColumn("jobXp","jobXp")
  2933. .addColumn("jobMoney","jobMoney")
  2934. .addColumn("jobMotivation","jobMotivation")
  2935. .addColumn("jobDistance","jobDistance")
  2936. .addColumn("jobAdd","jobAdd")
  2937. table.appendToCell("head","jobIcon","Job icon").appendToCell("head","jobName","Job name").appendToCell("head","jobXp",xpIcon + (Vajda.sortJobTableXp == 1 ? arrow_asc : Vajda.sortJobTableXp == -1 ? arrow_desc : "")).appendToCell("head","jobMoney",dollarIcon).appendToCell("head","jobMotivation",motivationIcon).appendToCell("head","jobDistance","Distance " + (Vajda.sortJobTableDistance == 1 ? arrow_asc : Vajda.sortJobTableDistance == -1 ? arrow_desc : "")).appendToCell("head","jobAdd","")
  2938. for ( let job = 0; job < uniqueJobs.length; job++ ) {
  2939. table
  2940. .appendRow()
  2941. .appendToCell(-1,"jobIcon",Vajda.getJobIcon(uniqueJobs[job].isSilver,uniqueJobs[job].id,uniqueJobs[job].x,uniqueJobs[job].y))
  2942. .appendToCell(-1,"jobName",Vajda.getJobName(uniqueJobs[job].id))
  2943. .appendToCell(-1,"jobXp",uniqueJobs[job].experience)
  2944. .appendToCell(-1,"jobMoney",uniqueJobs[job].money)
  2945. .appendToCell(-1,"jobMotivation",uniqueJobs[job].motivation)
  2946. .appendToCell(-1,"jobDistance",uniqueJobs[job].distance.formatDuration())
  2947. .appendToCell(-1,"jobAdd", Vajda.createAddJobButton(uniqueJobs[job].x,uniqueJobs[job].y,uniqueJobs[job].id))
  2948. }
  2949. const textfield = new west.gui.Textfield("jobsearch").setPlaceholder("Select job name")
  2950. if ( Vajda.jobFilter.filterJob !== "" ) {
  2951. textfield.setValue(Vajda.jobFilter.filterJob)
  2952. }
  2953.  
  2954. const checkboxOnlySilver = new west.gui.Checkbox()
  2955. checkboxOnlySilver.setLabel("Silvers")
  2956. checkboxOnlySilver.setSelected(Vajda.jobFilter.filterOnlySilver)
  2957. checkboxOnlySilver.setCallback(function() {
  2958. if ( this.isSelected() ) {
  2959. Vajda.jobFilter.filterOnlySilver = true
  2960. }else {
  2961. Vajda.jobFilter.filterOnlySilver = false
  2962. }
  2963. })
  2964. const checkboxNoSilver = new west.gui.Checkbox()
  2965. checkboxNoSilver.setLabel("No silvers")
  2966. checkboxNoSilver.setSelected(Vajda.jobFilter.filterNoSilver)
  2967. checkboxNoSilver.setCallback(function() {
  2968. if ( this.isSelected() ) {
  2969. Vajda.jobFilter.filterNoSilver = true
  2970. } else {
  2971. Vajda.jobFilter.filterNoSilver = false
  2972. }
  2973. })
  2974. const checkboxCenterJobs = new west.gui.Checkbox()
  2975. checkboxCenterJobs.setLabel("Center jobs")
  2976. checkboxCenterJobs.setSelected(Vajda.jobFilter.filterCenterJobs)
  2977. checkboxCenterJobs.setCallback(function() {
  2978. if ( this.isSelected() ) {
  2979. Vajda.jobFilter.filterCenterJobs = true
  2980. } else {
  2981. Vajda.jobFilter.filterCenterJobs = false
  2982. }
  2983. })
  2984. const buttonFilter = new west.gui.Button("Filter", function() {
  2985. Vajda.jobFilter.filterJob = textfield.getValue()
  2986. Vajda.jobTablePosition.content = "0px"
  2987. Vajda.jobTablePosition.scrollbar = "0px"
  2988. Vajda.selectTab("jobs")
  2989. })
  2990. htmlSkel.append(table.getMainDiv())
  2991. $('#jobFilter', html).append(textfield.getMainDiv())
  2992. $("#job_only_silver",html).append(checkboxOnlySilver.getMainDiv())
  2993. $("#job_no_silver",html).append(checkboxNoSilver.getMainDiv())
  2994. $("#job_center",html).append(checkboxCenterJobs.getMainDiv())
  2995. $("#button_filter_jobs",html).append(buttonFilter.getMainDiv())
  2996. htmlSkel.append(html)
  2997. return htmlSkel
  2998. }
  2999.  
  3000. Vajda.createAddJobButton = function(x, y, id) {
  3001. const buttonAdd = new west.gui.Button("Add new job", function() {
  3002. Vajda.addJob(x, y, id)
  3003. Vajda.jobTablePosition.content = $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css("top")
  3004. Vajda.jobTablePosition.scrollbar = $(".vajda-window .tw2gui_scrollbar_pulley").css("top")
  3005. Vajda.selectTab("jobs")
  3006. })
  3007. buttonAdd.setWidth(100)
  3008. return buttonAdd.getMainDiv()
  3009. }
  3010.  
  3011. Vajda.createMinMotivationTextfield = function(x, y, id, placeholder) {
  3012. const componentId = `x-${x}y-${y}id-${id}`
  3013. const textfield = new west.gui.Textfield()
  3014. textfield.setId(componentId)
  3015. textfield.setWidth(40)
  3016. textfield.setValue(placeholder)
  3017. return textfield.getMainDiv()
  3018. }
  3019.  
  3020. Vajda.createRemoveJobButton = function(x, y, id) {
  3021. const buttonRemove = new west.gui.Button("Remove job", function() {
  3022. Vajda.removeJob(x, y, id)
  3023. Vajda.addedJobTablePosition.content = $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css("top")
  3024. Vajda.addedJobTablePosition.scrollbar = $(".vajda-window .tw2gui_scrollbar_pulley").css("top")
  3025. Vajda.selectTab("chosenJobs")
  3026. })
  3027. buttonRemove.setWidth(100)
  3028. return buttonRemove.getMainDiv()
  3029. }
  3030.  
  3031.  
  3032. $(document).ready(() => {
  3033. try {
  3034. Vajda.loadLanguage()
  3035. Vajda.loadSets()
  3036. Vajda.createMenuIcon()
  3037. Vajda.getCookies()
  3038. Observer.resumeSession()
  3039. } catch(e) {
  3040. console.log(e)
  3041. console.log("exception occured")
  3042. }
  3043. })
  3044. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址