이 스크립트는 직접 설치해서 쓰는 게 아닙니다. 다른 스크립트가 메타 명령 // @require https://update.greasyfork.org/scripts/512872/1465973/Janka%20Tietzova.js
(으)로 포함하여 쓰는 라이브러리입니다.
// ==UserScript==
// @name Janka Tietzova
// @namespace http://tampermonkey.net/
// @version 2.1.1
// @description A user script for The West, optimized Dobby2 for butt plugs and cake decorations.
// @author Chvostnatý Gábor
// @include https://*.the-west.*/game.php*
// @license MIT
// @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==
// @grant none
// @downloadURL https://update.greasyfork.org/scripts/497915/Zdenka%20Studenkova.user.js
// @updateURL https://update.greasyfork.org/scripts/497915/Zdenka%20Studenkova.meta.js
// ==/UserScript==
(function() {
async function sleep(milliseconds) {
await new Promise(r => setTimeout(r, milliseconds))
}
function parseConsumableBonuses(bonuses) {
const { energyText, motivationText, healthText, speedText, luckText, dropText, experienceText, moneyText } = Vajda.searchKeys[Vajda.language]
const result = {
energy: 0,
health: 0,
motivation: 0,
hasBuffs: false,
buffs: {
character: {
luck: 0,
money: 0,
experience: 0,
drop: 0
},
travel: 0
}
}
function getValue(bonus, bonusText) {
return Number(bonus.toLowerCase().replace(bonusText.toLowerCase(), '').replace(' ', '').replace('%', '').replace('+', ''))
}
for (const bonus of bonuses) {
if ( bonus.includes(energyText) ) {
result.energy = getValue(bonus, energyText)
continue
}
if ( bonus.includes(motivationText) ) {
result.motivation = getValue(bonus, motivationText)
continue
}
if ( bonus.includes(healthText) ) {
result.health = getValue(bonus, healthText)
continue
}
if ( bonus.includes(speedText) ) {
result.buffs.travel = getValue(bonus, speedText)
result.hasBuffs = true
continue
}
if ( bonus.includes(luckText) ) {
result.buffs.character.luck = getValue(bonus, luckText)
result.hasBuffs = true
continue
}
if ( bonus.includes(experienceText) ) {
result.buffs.character.experience = getValue(bonus, experienceText)
result.hasBuffs = true
continue
}
if ( bonus.includes(moneyText) ) {
result.buffs.character.money = getValue(bonus, moneyText)
result.hasBuffs = true
continue
}
if ( bonus.includes(dropText) ) {
result.buffs.character.drop = getValue(bonus, dropText)
result.hasBuffs = true
}
}
return result
}
class Job {
constructor(x, y, id, groupId) {
this.x = x
this.y = y
this.id = id
this.groupId = groupId
this.isSilver = false
this.distances = []
this.experience = 0
this.money = 0
this.motivation = 0
this.stopMotivation = 75
this.set = -1
this.bestEquipment_ = undefined
}
setIsSilver(val) {
this.isSilver = val
return this
}
setExperience(val) {
this.experience = val
return this
}
setMoney(val) {
this.money = val
return this
}
setMotivation(valOrUpdater) {
if ( typeof valOrUpdater === 'function' ) {
this.motivation = valOrUpdater(this.motivation)
} else {
this.motivation = valOrUpdater
}
this.motivation = Math.min(100, this.motivation)
return this
}
setStopMotivation(val) {
this.stopMotivation = val
return this
}
setSet(index) {
this.set = index
return this
}
getDistances() {
return this.distances
}
async loadMotivation() {
await Ajax.get('job', 'job', {jobId: this.id, x: this.x, y: this.y}, (r) => {
this.motivation = r.motivation * 100
})
return this.motivation
}
/**
* Calculate job distance to current character position
*/
calculateDistance() {
this.distance = GameMap.calcWayTime({x: this.x, y: this.y}, Character.position)
return this.distance
}
/**
* Calculate job distance to other selected jobs
*/
calculateJobDistances() {
this.distances = []
for ( const job of Vajda.addedJobs ) {
this.distances.push(GameMap.calcWayTime({x: this.x, y: this.y}, {x: job.x, y: job.y}))
}
return this.distances
}
saveBestEquipment() {
const skills = JobsModel.Jobs.find(j => j.id === this.id).get('skills')
const set = west.item.Calculator.getBestSet(skills, this.id)
const itemIds = set && set.getItems() || []
this.bestEquipment_ = itemIds
return itemIds
}
get bestEquipment() {
return this.bestEquipment_ === undefined ? this.saveBestEquipment() : this.bestEquipment_
}
getBestEquipment() {
if (!Bag.loaded) {
EventHandler.listen('inventory_loaded', function() {
this.getBestEquipment()
return EventHandler.ONE_TIME_EVENT
})
return
}
const items = Bag.getItemsByItemIds(this.bestEquipment)
const result = []
for (const item of items) {
const wearItem = Wear.get(item.getType())
if (!wearItem || (wearItem && (wearItem.getItemBaseId() !== item.getItemBaseId() || wearItem.getItemLevel() < item.getItemLevel()))) {
result.push(item)
}
}
return result.map(item => item.obj.getId())
}
}
class Consumable {
constructor(id, image, name) {
this.id = id
this.image = image
this.name = name
this.energy = 0
this.motivation = 0
this.health = 0
this.isSelected_ = false
this.count = 0
}
isCakeDecoration() {
return this.id === 53339000
}
removeOne() {
this.count -= 1
if ( this.count === 0 ) {
const consumables = Manager.consumables
const index = consumables.findIndex(c => c.id === this.id)
consumables.splice(index, 1)
}
return this
}
setCount(valOrUpdater) {
if ( typeof valOrUpdater === 'function' ) {
this.count = valOrUpdater(this.count)
} else {
this.count = valOrUpdater
}
this.count = Math.max(0, this.count)
return this
}
setEnergy(val) {
this.energy = val
return this
}
setMotivation(val) {
this.motivation = val
return this
}
setHealth(val) {
this.health = val
return this
}
setIsSelected(isSelected) {
this.isSelected_ = isSelected
return this
}
hasCooldown() {
return this.energy > 0 || this.motivation > 0 || this.health > 0
}
getBuffHTML() {
return '<strong>No Buffs</strong>'
}
get isSelected() {
return this.isSelected_
}
}
class Buff extends Consumable {
constructor(id, image, name, buffs) {
super(id, image, name, buffs)
this.buffs_ = buffs
}
getBuffImage() {
return `https://westsk.innogamescdn.com/images/buffs/${this.getBuffType()}.jpg`
}
getBuffType() {
return this.buffs_.travel === 0 ? 'character' : 'travel'
}
canUseAsBuff() {
return CharacterSkills.buffs[this.getBuffType()] === null && !this.hasCooldown()
}
getBuffHTML() {
const containerStyle = `'
display: grid;
grid-template-columns: 30px auto;
'`
const imgContainerStyle = `'
display: flex;
padding-bottom: 5px;
'`
const buffsContainerStyle = `'
display: grid;
grid-template-rows: repeat(auto-fill, 15px);
transform: translateY(5px)
'`
const buffs = this.buffs.reduce((acc, b) => acc.concat(`<p>${b}</p>`), '')
const html = `
<div style=${containerStyle}>
<span style=${imgContainerStyle}>
<img style=align-self:end width=25px height=25px src=${this.getBuffImage()} alt='Buff Image'>
</span>
<span style=${buffsContainerStyle}>
${
buffs
}
</span>
</div>
`
return html
}
removeOne() {
this.count -= 1
if ( this.count === 0 ) {
const consumables = Manager.consumables
const buffs = Manager.buffs
let index = consumables.findIndex(c => c.id === this.id)
if ( index !== -1 ) {
consumables.splice(index, 1)
return this
}
index = buffs.findIndex(b => b.id === this.id)
if ( index !== -1 ) {
buffs.splice(index, 1)
if ( Manager.selectedBuffs.some(b => b.id === this.id) ) {
Manager.selectedBuffs_[this.getBuffType()] = null
}
}
}
return this
}
get isSelected() {
return Manager.selectedBuffs.some(b => b.id === this.id) || this.isSelected_
}
get buffs() {
if ( this.getBuffType() === 'travel' ) {
return [`+${this.buffs_.travel}% speed`]
}
const buffs = []
for ( const buff in this.buffs_.character ) {
if ( this.buffs_.character[buff] > 0 ) {
buffs.push(`+${this.buffs_.character[buff]}% ${buff}`)
}
}
return buffs
}
}
class ConsumablesManager {
selectedBuffs_ = {
travel: null,
character: null
}
constructor() {
this.consumables_ = []
this.buffs_ = []
this.isOptimized_ = false
this.jobsLeftInRound_ = 0
this.schedule_ = []
this.selectedBuffs_ = {
travel: null,
character: null
}
}
async loadJobMotivation(updatedJobsMotivation = undefined) {
let expectedJobCount = 0
const uniqueJobsCount = Vajda.addedJobs.length
if ( updatedJobsMotivation !== undefined ) {
expedtedJobCount = updatedJobsMotivation.reduce((acc, curr) => acc + curr, 0)
return { expectedJobCount, uniqueJobsCount }
}
for ( const job of Vajda.addedJobs ) {
expectedJobCount += Math.max(await job.loadMotivation() - job.stopMotivation, 0)
await sleep(500)
}
return { expectedJobCount, uniqueJobsCount }
}
async createSchedule(updatedJobsMotivation) {
const bottlePlugs = this.consumables.find(c => c.id === 52871000)
//in case the game runs in the background and the job to travel to is not canceled we gonna need extra energy point
//this is unlikely to happen but the energy wont go to waste anyway so why the fuck not
const { expectedJobCount, uniqueJobsCount } = await this.loadJobMotivation(updatedJobsMotivation)
this.jobsLeftInRound = expectedJobCount
const availableEnergy = Character.energy
const energyToFill = expectedJobCount + uniqueJobsCount - availableEnergy
const refillCount = Math.ceil(
energyToFill / ( bottlePlugs.energy / 100 * Character.maxEnergy )
)
//use plugs when n jobs left in round
const schedule = []
for ( let i = 0; i < refillCount; i++ ) {
//40 15s jobs in consumable cooldown
schedule.push(40 + i*40)
}
this.schedule_ = schedule
return schedule
}
isScheduledRefill() {
return this.isOptimized_ && this.refillsLeft > 0 && this.jobsLeftInRound <= this.schedule.at(-1)
}
async checkSchedule(jobCount) {
const bottlePlug = this.consumables.find(c => c.id === 52871000)
for ( let i = 0; i < jobCount; i++ ) {
this.jobsLeftInRound = p => p - 1
if ( this.isScheduledRefill() ) {
//the use of consumable blocks the start of new jobs for a short amount of time, so this sleep exists to prevent that
await sleep(10000)
this.useConsumableOrWaitForCooldown(bottlePlug)
this.schedule.pop()
this.jobsLeftInRound = p => p - (jobCount - i - 1)
return
}
}
if ( Character.energy - jobCount <= 10 ) {
//same here
await sleep(10000)
this.useConsumableOrWaitForCooldown(bottlePlug)
this.schedule.pop()
}
}
canUseConsumable(consumable) {
if ( consumable instanceof Buff ) {
return consumable.canUseAsBuff()
}
if ( BuffList.cooldowns[consumable.id] !== undefined && BuffList.cooldowns[consumable.id].time > new ServerDate().getTime() ) {
return false
}
return true
}
findProperConsumable(motivationMissing, energyMissing, averageMotivationMissing) {
const consumablesPool = this.getSelectedConsumables()
function betterEnergy(item1, item2) {
let distanceItem1 = Math.abs(energyMissing - item1.energy)
let distanceItem2 = Math.abs(energyMissing - item2.energy)
return (distanceItem1 < distanceItem2 ) ? -1 : (distanceItem1 > distanceItem2) ? 1 : 0
}
function betterMotivation(item1, item2) {
let distanceItem1 = Math.abs(averageMotivationMissing - item1.motivation)
let distanceItem2 = Math.abs(averageMotivationMissing - item2.motivation)
return (distanceItem2 < distanceItem1) ? item2 : item1
}
function findMotivationConsume(consumes) {
let consumeToChoose = null
for ( let i = 0; i < consumes.length; i++ ) {
if ( consumeToChoose === null && consumes[i].motivation !== 0) {
consumeToChoose = consumes[i]
continue
}
if ( consumeToChoose !== null && consumes[i].motivation !== 0) {
consumeToChoose = betterMotivation(consumeToChoose, consumables[i])
}
}
return consumeToChoose
}
function findHealthConsume(consumes) {
for ( let i = 0; i < consumes.length; i++ ) {
if ( consumes[i].health !== 0 ) {
return consumes[i]
}
}
return null
}
if ( consumablesPool.length === 0 ) return null
const consumables = consumablesPool.sort(betterEnergy)
if ( Vajda.settings.addEnergy && energyMissing === 100 ) {
return consumables[0]
}
if ( Vajda.settings.addMotivation && motivationMissing === Vajda.addedJobs.length ) {
return findMotivationConsume(consumables)
}
if ( Vajda.settings.addHealth && Vajda.isHealthBelowLimit() ) {
if ( this.isOptimized ) {
this.schedule.pop()
}
return findHealthConsume(consumables)
}
}
async useConsumable(consumable) {
const item = Bag.getItemByItemId(consumable.id)
item.showCooldown()
if ( Vajda.shouldEquipHealthSet(consumable) )
await Vajda.equipSet(Vajda.healthSet)
ItemUse.doIt(consumable.id)
consumable.removeOne()
while(true) {
if ( !this.canUseConsumable(consumable) ) {
$('.tw2gui_dialog_framefix').remove()
break
}
await sleep(1)
}
Vajda.currentState = 1
}
async useConsumableOrWaitForCooldown(consumableOrId, isSync = false) {
const consumable = consumableOrId instanceof Consumable ? consumableOrId : this.getSelectedConsumables().find(c => c.id === consumableOrId)
if ( consumable === undefined ) {
return false
}
Vajda.currentState = 2
while (true) {
if ( consumable.hasCooldown() === false || this.canUseConsumable(consumable) ) {
break
}
if ( !Vajda.isRunning ) {
break
}
await sleep(1000)
}
await this.useConsumable(consumable)
isSync && Vajda.run()
}
isConsumableAdded (item) {
if ( item === undefined )
return true
for ( const consumable of this.consumables_ ) {
if ( consumable.id === item.obj.item_id ) {
return true
}
}
for ( const buff of this.buffs_ ) {
if ( buff.id === item.obj.item_id ) {
return true
}
}
return false
}
useBuff(type) {
const buff = this.selectedBuffs_[type]
if ( buff?.canUseAsBuff() ) {
this.useConsumable(buff)
}
}
addNewConsumable(item) {
if ( this.isConsumableAdded(item) ) {
return
}
const { energy, motivation, health, hasBuffs, buffs } = parseConsumableBonuses(item.obj.usebonus)
if ( health === 0 && motivation === 0 && energy === 0 && !hasBuffs )
return
if ( hasBuffs ) {
const buff = new Buff(item.obj.item_id, item.obj.image, item.obj.name, buffs)
.setEnergy(energy)
.setMotivation(motivation)
.setHealth(health)
.setCount(item.count)
return buff.hasCooldown() ? this.consumables_.push(buff) : this.buffs_.push(buff)
}
const consumable = new Consumable(item.obj.item_id, item.obj.image, item.obj.name)
.setEnergy(energy)
.setMotivation(motivation)
.setHealth(health)
.setCount(item.count)
this.consumables.push(consumable)
}
hasEnoughPlugsAndDecorations() {
const bottlePlugs = this.consumables.find(c => c.id === 52871000)
const decorations = this.consumables.find(c => c.id === 53339000)
if ( !bottlePlugs || !decorations ) {
new UserMessage("No plugs or decorations were found, defaulting back to selected consumables", UserMessage.TYPE_HINT).show()
this.isOptimized_ = false
return false
}
return true
}
getSelectedConsumables() {
if ( this.isOptimized_ ) {
const bottlePlugs = this.consumables.find(c => c.id === 52871000)
const decorations = this.consumables.find(c => c.id === 53339000)
return [bottlePlugs, decorations]
} else {
return this.consumables.filter(c => c.isSelected === true)
}
}
addSelectedConsumable(val) {
if ( typeof val === 'number' )
this.consumables.at(val).isSelected = true
if ( val instanceof Consumable )
this.consumables.find(c => c.id === val.id).isSelected = true
}
get schedule() {
return this.schedule_
}
set schedule(val) {
this.schedule_ = val
}
get consumables() {
return this.consumables_
}
set consumables(val) {
this.consumables_ = val
}
get isOptimized() {
return this.isOptimized_
}
set isOptimized(valOrUpdater) {
if ( typeof valOrUpdater === 'function' ) {
this.isOptimized_ = valOrUpdater(this.isOptimized_)
} else {
this.isOptimized_ = valOrUpdater
}
}
get jobsLeftInRound() {
return this.jobsLeftInRound_
}
set jobsLeftInRound(valOrUpdater) {
if ( typeof valOrUpdater === 'function' ) {
this.jobsLeftInRound_ = valOrUpdater(this.jobsLeftInRound_)
} else {
this.jobsLeftInRound_ = valOrUpdater
}
}
get refillsLeft() {
return this.schedule.length
}
get buffs() {
return this.buffs_
}
get selectedBuffs() {
const res = []
for ( const type in this.selectedBuffs_ ) {
this.selectedBuffs_[type] && res.push(this.selectedBuffs_[type])
}
return res
}
set selectedBuffs(buff) {
const type = buff.getBuffType()
if ( this.selectedBuffs_[type]?.id === buff.id ) {
this.selectedBuffs_[type] = null
return
}
this.selectedBuffs_[type] = buff
new UserMessage(`New ${type} buff selected`, UserMessage.TYPE_SUCCESS).show()
}
}
class ActivityObserver {
constructor() {
const fiveMinutes = 5 * 60 * 1000
this.activityCheckTimeout_ = null
this.refreshCount = 0
this._isEnabled = false
this.timeOut_ = fiveMinutes
this.selectedConsumables = null
}
saveTempCookies() {
const selectedConsumables = Manager.consumables.reduce((acc, c) => {
c.isSelected && acc.push(c.id)
return acc
}, [])
const timeOut = this.timeOut_
const buffs = {
travel: Manager.selectedBuffs_.travel?.id || null,
character: Manager.selectedBuffs_.character?.id || null
}
const settings = {
statistics: Vajda.statistics,
selectedConsumables,
buffs,
timeOut,
direction: Vajda.direction,
currentJob: Vajda.currentJob,
refreshCount: this.refreshCount + 1,
schedule: Manager.schedule,
jobsLeftInRound: Manager.jobsLeftInRound,
travelSet: Vajda.travelSet,
jobSet: Vajda.jobSet,
healthSet: Vajda.healthSet
}
const expiracyDateTemporary = new Date()
const hour = expiracyDateTemporary.getHours()
expiracyDateTemporary.setHours(2,0,0)
if ( hour > 2 )
expiracyDateTemporary.setDate(expiracyDateTemporary.getDate() + 1)
document.cookie = `vajdasession=${JSON.stringify(settings)};expires=${expiracyDateTemporary.toGMTString()};`
}
getTempCookies() {
const cookies = document.cookie.split("=")
for ( let i = 0; i < cookies.length; i++ ) {
if ( cookies[i].includes("vajdasession") ) {
const {
timeOut, schedule, selectedConsumables, buffs, jobsLeftInRound, refreshCount, ...vajdaSettings
} = JSON.parse(cookies[i+1].split(";")[0])
this.selectedConsumables = selectedConsumables
this.buffs = buffs
this.refreshCount = refreshCount
this.timeOut_ = timeOut
this.isEnabled = true
Manager.jobsLeftInRound = jobsLeftInRound
Manager.schedule = schedule
Vajda = {...Vajda, ...vajdaSettings, isRunning: true}
document.cookie = 'vajdasession=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
return true
}
}
return false
}
restartSession() {
if ( Vajda.currentState === 2 ) {
this.start()
return
}
this.saveTempCookies()
location.reload()
}
resumeSession() {
Vajda.findAllConsumables()
if ( !this.getTempCookies() ) return
Vajda.createWindow(false)
Vajda.run()
}
start(forceStart = false) {
if ( !this.isEnabled && !forceStart ) return
clearTimeout(this.activityCheckTimeout_)
this.activityCheckTimeout_ = setTimeout(this.restartSession.bind(this), this.timeOut_)
}
stop() {
this.isEnabled = false
if ( this.activityCheckTimeout_ !== null )
clearTimeout(this.activityCheckTimeout_)
this.activityCheckTimeout_ = null
}
getTimeOut(convertToMinutes) {
if ( convertToMinutes ) {
return this.timeOut_ / 1000 / 60
}
return this.timeOut_
}
get isEnabled() {
return this._isEnabled
}
set isEnabled(valOrUpdater) {
if ( typeof valOrUpdater === 'function' ) {
this._isEnabled = valOrUpdater(this._isEnabled)
} else {
this._isEnabled = valOrUpdater
}
}
set timeOut(val) {
this.timeOut_ = Math.max(Number(val) * 60 * 1000, 2.5 * 60 * 1000)
}
}
window.Manager = new ConsumablesManager()
window.Observer = new ActivityObserver()
Vajda = {
addedJobs: [],
allJobs: [],
addedJobTablePosition: {
content: "0px",
scrollbar:"0px"
},
consumableSelection: {
energy: false,
motivation: false,
health: false,
hideBuffs: false
},
consumableTablePosition: {
content: '0px',
scrollbar: '0px'
},
consumableUsed: [],
currentJob: {
job: 0,
direction: true
},
currentState: 0,
healthSet: -1,
language: "",
isLoaded: false,
isRunning: false,
jobFilter: {
filterOnlySilver: false,
filterNoSilver: false,
filterCenterJobs: false,
filterJob: ""
},
jobSet: -1,
jobsLoaded: false,
jobTablePosition: {
content: "0px",
scrollbar: "0px"
},
lastJobStartTime: undefined,
states: [
'Idle',
'Running',
'Waiting for a consumable cooldown',
'Calculating optimal route'
],
statistics: {
sessionJobsCount: 0,
sessionXpCount: 0,
sessionMoneyCount: 0,
totalJobsCount: 0,
totalXpCount: 0,
totalMoneyCount: 0
},
selectedSet: 0,
sets: null,
settings: {
addEnergy: false,
addMotivation: false,
addHealth: false,
healthStop: 10,
setWearDelay: 5,
jobDelayMin: 0,
jobDelayMax: 0,
addDeposit: {
isEnabled: false,
limit: NaN
}
},
sortJobTableXp:0,
sortJobTableDistance:0,
travelSet: -1,
regenerationSet: -1,
window: null,
searchKeys: {
"en_DK":{
energy:"Energy",
energyText:"Energy increase:",
motivation:"Work motivation",
motivationText:"Work motivation increase:",
health: "Health point bonus",
healthText:"Health point bonus:"
},
"sk_SK": {
energy:"Energie",
energyText:"Zvýšenie energie:",
motivation:"Pracovnej motivácie",
motivationText:"Zvýšenie pracovnej motivácie:",
health: "Bonus bodov zdravia",
healthText:"Bonus bodov zdravia:",
speedText: "Rýchlosť",
experience: "skúseností",
experienceText: "Skúseností z práce, duelov a boja o pevnosť",
money: "peňazí",
moneyText: "Peňazí z práce a duelov",
luck: "šťastie",
luckText: "Vylepšené šťastie",
drop: "produktu",
dropText: "Vylepšenie šance na získanie produktu"
},
"cs_CZ":{
energy:"Energie",
energyText:"Zvýšení energie:",
motivation:"Pracovní motivace",
motivationText:"Zvýšení pracovní motivace:",
health: "Bonus zdraví",
healthText:"Bonus zdraví:",
speedText: "Rychlost",
experience: "zkušeností",
experienceText: "zkušeností z prací, duelů a bitev o pevnost",
money: "prací",
moneyText: "$ z prací a duelů",
luck: "štěstí",
luckText: "Vyšší šance na štěstí",
drop: "produktu",
dropText: "Vylepšené šance nálezu produktu"
},
"hu_HU":{
energy:"Energia növekedése:",
energyText:"Energia növekedése:",
motivation:"Munka motiváció növelése:",
motivationText:"Munka motiváció növelése:",
health: "Életerő bónusz",
healthText:"Életerő bónusz:"
},
"pl_PL":{
energy:"Wzrost energii:",
energyText:"Wzrost energii:",
motivation:"Zwiększenie motywacji do pracy:",
motivationText:"Zwiększenie motywacji do pracy:",
health: "Bonus Punktów życia:",
healthText:"Bonus Punktów życia:"
},
"ro_RO":{
energy:"Energie mărită:",
energyText:"Energie mărită:",
motivation:"Creştere a motivaţiei de muncă:",
motivationText:"Creştere a motivaţiei de muncă:",
health: "Puncte de viaţă:",
healthText:"Puncte de viaţă:"
}
}
}
Vajda.isNumber = function(potentialNumber) {
return Number.isInteger(parseInt(potentialNumber))
}
Vajda.RNG = function(min, max) {
let minN = Math.min(min, max)
let maxN = Math.max(min, max)
let number = Math.floor((minN + Math.random() * (maxN - minN + 1)))
return number
}
Vajda.isAllowedToDepositMoney = function() {
const hasMoreMoneyThanLimit = Vajda.settings.addDeposit.limit <= Character.money
const hasHomeTown = Character.homeTown.town_id !== 0
if ( hasHomeTown == false ) {
new UserMessage("You don't have a home town", UserMessage.TYPE_HINT).show()
return false
}
return Vajda.settings.addDeposit.isEnabled && hasMoreMoneyThanLimit
}
Vajda.getCookies = function() {
const cookies = document.cookie.split("=")
for ( let i = 0; i < cookies.length; i++ ) {
if ( cookies[i].includes("vajdatemporary") ) {
const obj = cookies[i+1].split(";")
const tempObject = JSON.parse(obj[0])
const tmpAddedJobs = tempObject.addedJobs
for ( const job of tmpAddedJobs ) {
const newJob = new Job(job.x, job.y, job.id, job.groupId)
newJob
.setIsSilver(job.isSilver)
.setExperience(job.experience)
.setMoney(job.money)
.setMotivation(job.motivation)
.setStopMotivation(job.stopMotivation)
.setSet(job.set)
Vajda.addedJobs.push(newJob)
}
Vajda.travelSet = tempObject.travelSet
Vajda.jobSet = tempObject.jobSet
Vajda.healthSet = tempObject.healthSet
Vajda.currentJob = tempObject.currentJob
Vajda.setSetForAllJobs()
}
if ( cookies[i].includes("vajdapermanent") ) {
const obj = cookies[i+1].split(";")
const permanentObject = JSON.parse(obj[0])
const { isOptimized, isEnabled, timeOut, ...settings } = permanentObject.settings
Manager.isOptimized = !!isOptimized
Observer.isEnabled = !!isEnabled
Observer.timeOut = timeOut || 5
Vajda.settings = settings
if ( !settings.addDeposit ) {
Vajda.settings.addDeposit = {
isEnabled: false,
limit: NaN
}
}
Vajda.statistics.totalJobsCount = Math.floor(permanentObject.totalJobs)
Vajda.statistics.totalXpCount = permanentObject.totalXp
Vajda.statistics.totalMoneyCount = permanentObject.totalMoney
}
}
}
Vajda.setCookies = function() {
let expiracyDateTemporary = new Date()
let hour = expiracyDateTemporary.getHours()
expiracyDateTemporary.setHours(2,0,0)
if ( hour > 2 )
expiracyDateTemporary.setDate(expiracyDateTemporary.getDate() + 1)
const addedJobs = Vajda.addedJobs.map(j => ({
x: j.x,
y: j.y,
id: j.id,
groupId: j.groupId,
isSilver: j.isSilver,
experience: j.experience,
money: j.money,
motivation: j.motivation,
stopMotivation: j.stopMotivation,
set: j.set
}))
let temporaryObject = {
addedJobs,
travelSet: Vajda.travelSet,
jobSet: Vajda.jobSet,
healthSet: Vajda.healthSet,
currentJob: Vajda.currentJob
}
let expiracyDatePernament = new Date()
expiracyDatePernament.setDate(expiracyDatePernament.getDate() + 360000)
let pernamentObject = {
settings: {...Vajda.settings, isOptimized: Manager.isOptimized, isEnabled: Observer.isEnabled, timeOut: Observer.getTimeOut(true)},
totalJobs: Vajda.statistics.totalJobsCount,
totalXp: Vajda.statistics.totalXpCount,
totalMoney: Vajda.statistics.totalMoneyCount
}
const jsonTemporary = JSON.stringify(temporaryObject)
const jsonPernament = JSON.stringify(pernamentObject)
document.cookie = `vajdatemporary=${jsonTemporary};expires=${expiracyDateTemporary.toGMTString()};`
document.cookie = `vajdapermanent=${jsonPernament};expires=${expiracyDatePernament.toGMTString()};`
}
Vajda.shouldEquipHealthSet = function(consumable) {
if ( !consumable.hasCooldown() ) {
return false
}
if ( Manager.isOptimized ) {
return false
}
return consumable.health > 0 && Vajda.healthSet > -1
}
Vajda.parseConsumableBonuses = function(bonuses) {
let getBonus = (text,type) => {
switch(type) {
case 0:
text = text.replace(Vajda.searchKeys[Vajda.language].energyText,"")
break
case 1:
text = text.replace(Vajda.searchKeys[Vajda.language].motivationText,"")
break
case 2:
text = text.replace(Vajda.searchKeys[Vajda.language].healthText,"")
break
}
text = text.slice(1)
text = text.replace("%","")
return parseInt(text)
}
let result = Array(3).fill(0)
for ( let i = 0 ; i < bonuses.length; i++ ) {
let type = -1
if ( bonuses[i].includes(Vajda.searchKeys[Vajda.language].energyText) ) {
type = 0
}else if ( bonuses[i].includes(Vajda.searchKeys[Vajda.language].motivationText) ) {
type = 1
}else if ( bonuses[i].includes(Vajda.searchKeys[Vajda.language].healthText) ) {
type = 2
}
if ( type !=-1 )
result[type] = getBonus(bonuses[i],type)
}
return result
}
Vajda.findAllConsumables = function() {
if ( Vajda.searchKeys[Vajda.language] === undefined ) return
const energyConsumables = Bag.search(Vajda.searchKeys[Vajda.language].energy)
for ( const consumable of energyConsumables ) {
Manager.addNewConsumable(consumable)
}
const motivationConsumables = Bag.search(Vajda.searchKeys[Vajda.language].motivation)
for ( const consumable of motivationConsumables ) {
Manager.addNewConsumable(consumable)
}
const healthConsumables = Bag.search(Vajda.searchKeys[Vajda.language].health)
for ( const consumable of healthConsumables ) {
Manager.addNewConsumable(consumable)
}
const speedConsumables = Bag.search(Vajda.searchKeys[Vajda.language].speedText)
for ( const consumable of speedConsumables ) {
if ( consumable.obj.usetype !== 'none' ) {
Manager.addNewConsumable(consumable)
}
}
const luckConsumables = Bag.search(Vajda.searchKeys[Vajda.language].luck)
for ( const consumable of luckConsumables ) {
if ( consumable.obj.usetype !== 'none' ) {
Manager.addNewConsumable(consumable)
}
}
const experienceConsumables = Bag.search(Vajda.searchKeys[Vajda.language].experience)
for ( const consumable of experienceConsumables ) {
if ( consumable.obj.usetype !== 'none' ) {
Manager.addNewConsumable(consumable)
}
}
const moneyConsumables = Bag.search(Vajda.searchKeys[Vajda.language].money)
for ( const consumable of moneyConsumables ) {
if ( consumable.obj.usetype !== 'none' ) {
Manager.addNewConsumable(consumable)
}
}
const dropConsumables = Bag.search(Vajda.searchKeys[Vajda.language].drop)
for ( const consumable of dropConsumables ) {
if ( consumable.obj.usetype !== 'none' ) {
Manager.addNewConsumable(consumable)
}
}
Observer.selectedConsumables?.forEach(id => {
Manager.consumables.find(c => c.id === id).setIsSelected(true)
})
for ( const type in Observer.buffs ) {
Manager.selectedBuffs_[type] = Manager.buffs_.find(b => b.id === Observer.buffs[type]) || null
}
Observer.selectedConsumables = null
Observer.buffs = null
}
Vajda.filterConsumables = function(energy, motivation, health, hideBuffs) {
const result = hideBuffs ? [] : [...Manager.buffs]
for ( const consumable of Manager.consumables ) {
if ( energy && consumable.energy === 0 ) {
continue
}
if ( motivation && consumable.motivation === 0 ) {
continue
}
if ( health && consumable.health === 0 ) {
continue
}
result.push(consumable)
}
return result
}
Vajda.changeConsumableSelection = function(id, isSelected) {
Manager.consumables.find(c => c.id === id)?.setIsSelected(isSelected)
}
Vajda.changeSelectionAllConsumables = function(selected) {
for ( const consumable of Manager.consumables ) {
consumable.setIsSelected(selected)
}
}
Vajda.loadJobs = function() {
if ( !Vajda.jobsLoaded ) {
new UserMessage("Loading...", UserMessage.TYPE_HINT).show()
let index = 0
let currentLength = 0
let maxLength = 299
Ajax.get('map', 'get_minimap', {}, function(r) {
var tiles = []
var jobs = []
for ( let townNumber in r.towns ) {
if ( r.towns[townNumber].town_id === Character.homeTown.town_id ) {
Vajda.homeTown = r.towns[townNumber]
break
}
}
for ( let jobGroup in r.job_groups ) {
const groupId = parseInt(jobGroup)
let group = r.job_groups[jobGroup]
let jobsGroup = JobList.getJobsByGroupId(groupId)
for ( let tilecoord = 0; tilecoord < group.length; tilecoord++ ) {
let xCoord = Math.floor(group[tilecoord][0]/GameMap.tileSize)
let yCoord = Math.floor(group[tilecoord][1]/GameMap.tileSize)
if ( currentLength == 0 ) {
tiles[index] = []
}
tiles[index].push([xCoord,yCoord])
currentLength++
if ( currentLength === maxLength ) {
currentLength = 0
index++
}
for ( let i = 0; i < jobsGroup.length; i++ ) {
jobs.push(new Job(group[tilecoord][0],group[tilecoord][1],jobsGroup[i].id, groupId))
}
}
}
let toLoad = tiles.length
let loaded = 0
for ( let blocks = 0; blocks < tiles.length; blocks++ ) {
GameMap.Data.Loader.load(tiles[blocks], function() {
loaded++
if ( loaded === toLoad ) {
Vajda.jobsLoaded = true
Vajda.allJobs = jobs
Vajda.findAllConsumables()
Vajda.createWindow()
}
})
}
})
} else {
Vajda.findAllConsumables()
Vajda.createWindow()
}
}
Vajda.loadJobData = function(callback) {
Ajax.get('work','index', {}, function(r) {
if( r.error ) {
console.log(r.error)
return
}
JobsModel.initJobs(r.jobs)
callback()
})
}
Vajda.getJobSet = function(x, y, id) {
const job = Vajda.findAddedJob(x, y, id)
if ( job !== null )
return job.set
}
Vajda.setJobSet = function(x,y,id,set) {
const job = Vajda.findAddedJob(x, y, id)
if ( job !== null)
return job.setSet(set)
}
Vajda.findAddedJob = function(x, y, id) {
for ( const job of Vajda.addedJobs ) {
if ( job.x === x && job.y === y && job.id === id ) {
return job
}
}
return null
}
Vajda.loadSets = async function(callback) {
Ajax.remoteCallMode('inventory', 'show_equip', {}, function(r) {
Vajda.sets = r.data
if ( callback !== undefined )
callback()
})
}
Vajda.loadJobMotivation = function(index, callback) {
const job = Vajda.addedJobs.at(index)
Ajax.get('job', 'job', {jobId: job.id, x: job.x, y: job.y}, function(r) {
if ( callback !== undefined )
callback(r.motivation*100)
})
}
Vajda.loadLanguage = function() {
Ajax.remoteCall("settings", "settings", {}, function(resp) {
Vajda.language = resp.lang.account.key
})
}
Vajda.getConsumableIcon = function(src) {
return `<div><img src='${src}'></div>`
}
Vajda.getItemImage = function(id) {
return ItemManager.get(id).wear_image
}
Vajda.createComboxJobSets = function(x, y, id) {
let combobox = new west.gui.Combobox()
Vajda.addComboboxItems(combobox)
combobox = combobox.select(Vajda.getJobSet(x, y, id))
combobox.setWidth(60)
combobox.addListener(function(value) {
Vajda.setJobSet(x, y, id, value)
Vajda.selectTab("chosenJobs")
});
return combobox.getMainDiv()
}
Vajda.addComboboxItems = function(combobox) {
combobox.addItem(-1, "None")
for ( let i = 0 ; i < Vajda.sets.length; i++) {
combobox.addItem(i.toString(), Vajda.sets[i].name)
}
}
Vajda.updateJobDistances = function() {
for ( let i = 0; i < Vajda.allJobs.length; i++ ) {
Vajda.allJobs[i].calculateDistance()
}
}
Vajda.findJobData = function(job) {
for ( let i = 0 ;i < JobsModel.Jobs.length; i++ ) {
if ( JobsModel.Jobs[i].id === job.id ) {
return JobsModel.Jobs[i]
}
}
}
Vajda.findJob = function(x, y, id) {
for ( let i = 0; i < Vajda.allJobs.length; i++ ) {
if ( Vajda.allJobs[i].id === id && Vajda.allJobs[i].x === x && Vajda.allJobs[i].y === y ) {
return Vajda.allJobs[i]
}
}
}
Vajda.addJob = function(x, y, id) {
if ( !Vajda.checkIfJobAdded(id) ) {
Vajda.addedJobs.push(Vajda.findJob(x, y, id))
}
}
Vajda.removeJob = function(x, y, id) {
for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
if ( Vajda.addedJobs[i].id === id && Vajda.addedJobs[i].x === x && Vajda.addedJobs[i].y === y) {
Vajda.addedJobs.splice(i,1)
Vajda.consolidePosition(i)
break
}
}
}
Vajda.parseJobData = function(jobs) {
for ( let job = 0; job < jobs.length; job++ ) {
let currentJob = jobs[job]
let data = Vajda.findJobData(currentJob)
let xp = data.basis.short.experience
let money = data.basis.short.money
currentJob.setMotivation(data.jobmotivation*100)
if ( currentJob.isSilver ) {
xp = Math.ceil(1.5*xp)
money = Math.ceil(1.5*money)
}
currentJob.setExperience(xp)
currentJob.setMoney(money)
}
}
Vajda.getJobName = function(id) {
return JobList.getJobById(id).name
}
Vajda.getJobIcon = function(isSilver, id, x, y) {
return `
<div class="job" style="left: 0; top: 0; position: relative;">
<div onclick="JobWindow.open(${id}, ${x}, ${y})" class="featured ${isSilver && 'silver'}"></div>
<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>
<img src="../images/jobs/${JobList.getJobById(id).shortname}.png" class="job_icon" alt='job_image'>
</div>
`
}
Vajda.checkIfJobAdded = function(id) {
for ( const job of Vajda.addedJobs ) {
if ( job.id === id ) {
return true
}
}
return false
}
Vajda.isJobSilver = function(x, y, id) {
const key = `${x}-${y}`
const jobData = GameMap.JobHandler.Featured[key]
if ( jobData === undefined || jobData[id] === undefined ) {
return false
} else {
return jobData[id].silver
}
}
Vajda.compareUniqueJobs = function(job, jobs){
for ( let i = 0 ; i < jobs.length; i++ ) {
if ( jobs[i].id === job.id ) {
if ( job.isSilver && !jobs[i].isSilver || (job.isSilver === jobs[i].isSilver && job.distance < jobs[i].distance) ) {
const j = jobs.at(i)
if ( !Vajda.isJobSilver(j.x, j.y, j.id) )
jobs.splice(i,1)
jobs.push(job)
}
return
}
}
jobs.push(job)
}
Vajda.getAllUniqueJobs = function() {
Vajda.updateJobDistances()
let jobs = []
for ( let i = 0 ; i < Vajda.allJobs.length; i++ ) {
const currentJob = Vajda.allJobs.at(i)
if ( Vajda.jobFilter.filterJob !== "" ) {
if ( !Vajda.getJobName(currentJob.id).toLowerCase().includes(Vajda.jobFilter.filterJob)) {
continue
}
}
if ( Vajda.checkIfJobAdded(currentJob.id) ) {
continue
}
let isSilver = Vajda.isJobSilver(currentJob.x, currentJob.y, currentJob.id)
currentJob.isSilver = isSilver
currentJob.calculateDistance()
if ( isSilver && Vajda.jobFilter.filterNoSilver ) {
continue
}
if ( !isSilver && Vajda.jobFilter.filterOnlySilver ) {
continue
}
if ( Vajda.jobFilter.filterCenterJobs && currentJob.id < 131 ) {
continue
}
Vajda.compareUniqueJobs(currentJob, jobs)
}
Vajda.parseJobData(jobs)
let experienceSort = function(a, b) {
if ( a === null && b === null ) {
return 0
}
if ( a === null && b !== null ) {
return 1
}
if ( a !== null && b === null ) {
return -1
}
let a1 = a.experience
let b1 = b.experience
return (a1 > b1) ? -1 :(a1 < b1) ? 1 :0
}
let reverseExperienceSort = function(a, b) {
if ( a === null && b === null ) {
return 0
}
if ( a === null && b !== null ) {
return -1
}
if ( a !== null && b === null ) {
return 1
}
let a1 = a.experience
let b1 = b.experience
return (a1 > b1) ? 1 :(a1 < b1) ? -1 :0
}
let distanceSort = function(a, b) {
if ( a === null && b === null ) {
return 0
}
if ( a === null && b !== null ) {
return 1
}
if ( a !== null && b === null ) {
return -1
}
let a1 = a.distance
let b1 = b.distance
return (a1 > b1) ? -1 :(a1 < b1) ? 1 :0
}
let reverseDistanceSort = function(a, b) {
if ( a === null && b === null ) {
return 0
}
if ( a === null && b !== null ) {
return -1
}
if(a !== null && b === null ) {
return 1
}
let a1 = a.distance
let b1 = b.distance
return (a1 > b1) ? 1 :(a1 < b1) ? -1 :0
}
if ( Vajda.sortJobTableXp === 1 ) {
jobs.sort(experienceSort)
}
if ( Vajda.sortJobTableXp === -1 ) {
jobs.sort(reverseExperienceSort)
}
if ( Vajda.sortJobTableDistance === 1 ) {
jobs.sort(distanceSort)
}
if ( Vajda.sortJobTableDistance === -1 ) {
jobs.sort(reverseDistanceSort)
}
return jobs
}
Vajda.parseStopMotivation = function() {
for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
let stopMotivation = $(".vajda-window #x-" + Vajda.addedJobs[i].x + "y-" + Vajda.addedJobs[i].y + "id-" + Vajda.addedJobs[i].id).prop("value")
if ( Vajda.isNumber(stopMotivation) ) {
Vajda.addedJobs[i].setStopMotivation(parseInt(stopMotivation))
} else {
return false
}
}
return true
}
Vajda.setSetForAllJobs = function() {
for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
Vajda.addedJobs[i].setSet(Vajda.jobSet)
}
}
Vajda.consolidePosition = function(removeIndex) {
if ( removeIndex <= Vajda.currentJob.job && Vajda.currentJob.job > 0 ) {
Vajda.currentJob.job--
}
if ( Vajda.addedJobs.length === 1 ) {
Vajda.currentJob.direction = true
}
}
Vajda.createDistanceMatrix = function() {
const matrix = new Array(Vajda.addedJobs.length)
for ( let i = 0; i < matrix.length; i++ ) {
matrix[i] = Vajda.addedJobs[i].calculateJobDistances()
}
return matrix
}
Vajda.countSetBits = function(n) {
let count = 0
while (n) {
n &= n - 1
count++
}
return count
}
Vajda.heldKarpSymmetric = function(distances, startJob) {
const n = distances.length
const memo = Array(1 << n).fill().map(() => Array(n).fill({ cost: Infinity, path: [] }))
memo[1 << startJob][startJob] = { cost: 0, path: [startJob] }
for ( let subsetSize = 2; subsetSize <= n; subsetSize++ ) {
for ( let subset = 0; subset < (1 << n); subset++ ) {
if ( Vajda.countSetBits(subset) === subsetSize && (subset & (1 << startJob)) ) {
for ( let end = 0; end < n; end++ ) {
if ( (subset & (1 << end)) !== 0 ) {
for ( let prevEnd = 0; prevEnd < n; prevEnd++ ) {
if ( prevEnd !== end && (subset & (1 << prevEnd)) !== 0 ) {
const newCost = memo[subset ^ (1 << end)][prevEnd].cost + distances[prevEnd][end]
if (newCost < memo[subset][end].cost) {
memo[subset][end] = { cost: newCost, path: memo[subset ^ (1 << end)][prevEnd].path.concat([end]) }
}
}
}
}
}
}
}
}
let minCost = Infinity
let minPath = []
for ( let end = 0; end < n; end++ ) {
if ( end !== startJob && memo[(1 << n) - 1][end].cost < minCost ) {
minCost = memo[(1 << n) - 1][end].cost
minPath = memo[(1 << n) - 1][end].path
}
}
return { cost: minCost, path: minPath }
}
Vajda.setEntryPoint = function(route) {
const firstJob = route.at(0)
const lastJob = route.at(-1)
if ( firstJob.calculateDistance() > lastJob.calculateDistance() )
route.reverse()
//i could in theory make vajda start with the job nearest to current character position but cba
}
Vajda.getOptimalRoute = function(distanceMatrix) {
const jobsCount = distanceMatrix.length
if ( jobsCount === 1 )
return {
cost: 0,
path: [0]
}
const routes = []
for ( let startJob = 0; startJob < jobsCount; startJob++ ) {
const { cost, path } = Vajda.heldKarpSymmetric(distanceMatrix, startJob)
routes.push({ cost, path })
}
return routes.reduce(function(prev, curr) {
return prev.cost < curr.cost ? prev : curr
})
}
Vajda.createRoute = function() {
Vajda.currentJob = {
job: 0,
direction: true
}
const distanceMatrix = Vajda.createDistanceMatrix()
const optimalRoute = Vajda.getOptimalRoute(distanceMatrix)
const addedJobsOrder = []
for ( const index of optimalRoute.path ) {
addedJobsOrder.push(Vajda.addedJobs.at(index))
}
Vajda.setEntryPoint(addedJobsOrder)
Vajda.addedJobs = addedJobsOrder
Vajda.selectTab("chosenJobs")
}
Vajda.createSetGui = function() {
if ( Vajda.sets.length === 0 ) {
return $(`<span style='font-size: 20px'>No sets available</span>`)
}
let htmlSkel = $(`
<div id='vajda_sets_window' style='display: block; position: relative; width: 650px; height:430px'>
<div id='vajda_sets_left' style='display: block; position: absolute; width: 250px; height: 430px; top:0px; left:0px'></div>
<div id='vajda_sets_right' style='display: block; position: absolute; width:300px; height: 410px; top: 0px; left: 325px'></div>
</div>`)
let combobox = new west.gui.Combobox("combobox_sets")
Vajda.addComboboxItems(combobox)
combobox = combobox.select(Vajda.selectedSet)
combobox.addListener(function(value) {
Vajda.selectedSet = value
Vajda.selectTab("sets")
})
let buttonSelectTravelSet = new west.gui.Button("Select travel set", function() {
Vajda.travelSet = Vajda.selectedSet
Vajda.selectTab("sets")
})
let buttonSelectJobSet = new west.gui.Button("Select job set", function() {
Vajda.jobSet = Vajda.selectedSet
Vajda.setSetForAllJobs()
Vajda.selectTab("sets")
})
let buttonSelectHealthSet = new west.gui.Button("Select health set", function() {
Vajda.healthSet = Vajda.selectedSet
Vajda.selectTab("sets")
})
let buttonSelectRegenSet = new west.gui.Button("Select regeneration set", function() {
Vajda.regenerationSet = Vajda.selectedSet
Vajda.selectTab("sets")
})
let travelSetText = "None"
if ( Vajda.travelSet != -1 ) {
travelSetText = Vajda.sets[Vajda.travelSet].name
}
let jobSetText = "None"
if ( Vajda.jobSet != -1 ) {
jobSetText = Vajda.sets[Vajda.jobSet].name
}
let healthSetText = "None"
if ( Vajda.healthSet != -1 ) {
healthSetText = Vajda.sets[Vajda.healthSet].name
}
let regenSetText = "None"
if ( Vajda.regenerationSet != -1 ) {
regenSetText = Vajda.sets[Vajda.regenerationSet].name
}
const left = $("<div></div>")
.append(
new west.gui.Groupframe()
.appendToContentPane($("<span>Sets</span><br><br>"))
.appendToContentPane(combobox.getMainDiv())
.appendToContentPane($("<br><br><span>Travel set:"+ travelSetText +"</span><br><br>"))
.appendToContentPane(buttonSelectTravelSet.getMainDiv())
.appendToContentPane($("<br><br><span>Job set:"+ jobSetText +"</span><br><br>"))
.appendToContentPane(buttonSelectJobSet.getMainDiv())
.appendToContentPane($("<br><br><span>Health set:"+ healthSetText +"</span><br><br>"))
.appendToContentPane(buttonSelectHealthSet.getMainDiv())
.getMainDiv()
)
const right = $("<div style=\'display:block; position:relative; width:300px; height:410px'\></div>")
//head div
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>")
//chest div
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>")
//pants div
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>")
//neck div
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>")
//right arm div
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>")
//animal div
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>")
//yield div
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>")
//left arm div
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>")
//belt div
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>")
//boots div
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>")
let keys = ["head","body","pants","neck","right_arm","animal","yield","left_arm","belt","foot"]
if ( Vajda.selectedSet !== -1 )
Vajda.insertSetImages(right,keys)
$("#vajda_sets_left",htmlSkel).append(left)
$("#vajda_sets_right",htmlSkel).append(right)
return htmlSkel
}
Vajda.getImageSkel = function() {
return $("<img src=\''\>")
}
Vajda.insertSetImages = function(html,keys) {
for ( let i = 0; i < keys.length; i++ ) {
if ( Vajda.sets[Vajda.selectedSet][keys[i]] !== null ) {
$(".wear_"+keys[i], html).append(Vajda.getImageSkel().attr("src", Vajda.getItemImage(Vajda.sets[Vajda.selectedSet][keys[i]])))
}
}
return html
}
Vajda.addEventsHeader = function() {
$(".vajda-window .jobXp").click(function() {
if ( Vajda.sortJobTableXp === 0 ) {
Vajda.sortJobTableXp = 1
} else {
( Vajda.sortJobTableXp === 1 ) ? Vajda.sortJobTableXp = -1 : Vajda.sortJobTableXp = 1
}
Vajda.sortJobTableDistance = 0
Vajda.selectTab("jobs")
})
$(".vajda-window .jobDistance").click(function() {
if ( Vajda.sortJobTableDistance === 0 ) {
Vajda.sortJobTableDistance = 1
} else {
( Vajda.sortJobTableDistance === 1 ) ? Vajda.sortJobTableDistance = -1 : Vajda.sortJobTableDistance = 1
}
Vajda.sortJobTableXp = 0
Vajda.selectTab("jobs")
})
}
Vajda.isInHomeTown = function() {
const homeTown = Character.homeTown
return GameMap.calcWayTime(Character.position,{x: homeTown.x, y: homeTown.y}) == 0
}
Vajda.addDeposit = async function(townId) {
const amount = Character.money
await Ajax.remoteCall("building_bank", "deposit", {
town_id: townId,
amount: amount
}, function(data) {
if (data.error == false) {
BankWindow.Balance.Mupdate(data)
Character.setDeposit(data.deposit)
Character.setMoney(data.own_money)
//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()
} else
new UserMessage(data.msg,UserMessage.TYPE_ERROR).show()
}, BankWindow)
}
Vajda.goDepositMoney = async function() {
const townId = Character.homeTown.town_id
if ( !townId ) return
await Vajda.equipSet(Vajda.travelSet)
TaskQueue.add(new TaskWalk(townId, 'town'))
while(true) {
if ( Vajda.isInHomeTown() ) {
break
}
if( !Vajda.isRunning ) {
break
}
await sleep(1000)
}
await Vajda.addDeposit(townId)
$('.tw2gui_dialog_framefix').remove()
}
Vajda.updateJobsMotivationOnRefill = function(val) {
return Vajda.addedJobs.map(job => job.setMotivation(p => p + val).motivation - job.stopMotivation)
}
Vajda.checkMotivation = async function(index, result, callback) {
let check = function(index, result) {
Vajda.loadJobMotivation(index, function(motivation) {
Vajda.addedJobs.at(index).setMotivation(motivation)
result.push(motivation)
if ( index + 1 < Vajda.addedJobs.length ) {
check(++index, result)
} else if( index + 1 === Vajda.addedJobs.length ) {
callback(result)
return
}
})
}
check(index, result)
}
Vajda.isMotivationAbove = function(result) {
for ( let i = 0; i < result.length; i++ ) {
if ( result.at(i) > Vajda.addedJobs.at(i).stopMotivation ) {
return true
}
}
return false
}
Vajda.isStopMotivationZero = function() {
for ( let i = 0; i < Vajda.addedJobs.length; i++ ) {
if( Vajda.addedJobs[i].stopMotivation === 0 ) {
return true
}
}
return false
}
Vajda.isHealthBelowLimit = function() {
if ( Vajda.settings.healthStop >= ((Character.health/Character.maxHealth) * 100) ) {
return true
}
return false
}
Vajda.changeJob = function() {
Vajda.currentJob.direction ? Vajda.currentJob.job++ : Vajda.currentJob.job--;
if ( Vajda.currentJob.job === Vajda.addedJobs.length ) {
Vajda.currentJob.job--
Vajda.currentJob.direction = false
} else if ( Vajda.currentJob.job < 0 ) {
Vajda.currentJob.job++
Vajda.currentJob.direction = true
}
Vajda.setCookies()
Vajda.run()
}
Vajda.searchBest = function(skills, jobId, onlyWearable = true) {
if (!Bag.loaded) {
EventHandler.listen('inventory_loaded', function() {
Vajda.searchBest(skills, jobId, onlyWearable)
return EventHandler.ONE_TIME_EVENT
})
return
}
let set = west.item.Calculator.getBestSet(skills, jobId), items = set && set.getItems() || [], invItems = Bag.getItemsByItemIds(items), result = [], i, invItem, wearItem
for (i = 0; i < invItems.length; i++) {
invItem = invItems[i]
wearItem = Wear.get(invItem.getType())
if (!wearItem || (wearItem && (wearItem.getItemBaseId() !== invItem.getItemBaseId() || wearItem.getItemLevel() < invItem.getItemLevel()))) {
result.push(invItem)
}
}
return result.map(item => item.obj.getId())
}
Vajda.getBestGear = function(jobid) {
let modelId = function(jobid) {
for ( let i = 0; i < JobsModel.Jobs.length; i++ ) {
if ( JobsModel.Jobs[i].id === jobid )
return i
}
return -1
}
const result = west.item.Calculator.getBestSet(JobsModel.Jobs[modelId(jobid)].get('skills'), jobid)
const bestItems = result && result.getItems()
return bestItems
}
Vajda.isWearing = function(itemId) {
if ( Wear.wear[ItemManager.get(itemId).type] === undefined) return false
return Wear.wear[ItemManager.get(itemId).type].obj.item_id == itemId
}
Vajda.isGearEquiped = async function(items) {
for ( const itemId of items ) {
if ( !Vajda.isWearing(itemId) ) {
return false
}
}
return true
}
Vajda.equipBestGear = async function(job) {
const bestGear = job.getBestEquipment()
for ( const itemId of bestGear ) {
Wear.carry(Bag.getItemByItemId(itemId))
}
while (true) {
const isFinished = await Vajda.isGearEquiped(bestGear)
if ( isFinished ) break
await sleep(50)
}
return Promise.resolve(true)
}
Vajda.getSetItemArray = function(set) {
var items = []
if ( set.head !== null )
items.push(set.head)
if ( set.neck !== null )
items.push(set.neck)
if ( set.body !== null )
items.push(set.body)
if ( set.right_arm !== null )
items.push(set.right_arm)
if ( set.left_arm !== null )
items.push(set.left_arm)
if ( set.belt !== null )
items.push(set.belt)
if ( set.foot !== null )
items.push(set.foot)
if ( set.animal !== null )
items.push(set.animal)
if ( set.yield !== null )
items.push(set.yield)
if ( set.pants !== null )
items.push(set.pants)
return items
}
Vajda.equipSet = async function(set) {
if ( set === -1 ) return true
EquipManager.switchEquip(Vajda.sets[set].equip_manager_id)
while ( true ) {
let isFinished = await Vajda.isGearEquiped(Vajda.getSetItemArray(Vajda.sets[set]))
if ( isFinished ) break
await sleep(50)
}
return Promise.resolve(true)
}
Vajda.cancelJobs = function() {
if ( TaskQueue.queue.length > 0 )
TaskQueue.cancelAll()
}
//https://prnt.sc/KAgbLNqB4zK6
Vajda.runJob = async function(jobIndex, jobCount) {
Vajda.statistics.sessionJobsCount += jobCount
Vajda.statistics.totalJobsCount += jobCount
const oldXp = Character.experience
const oldMoney = Character.money
const job = Vajda.addedJobs.at(jobIndex)
await Vajda.equipBestGear(job)
for ( let i = 0; i < jobCount; i++ ) {
JobWindow.startJob(job.id, job.x, job.y, 15)
}
Observer.start()
await sleep(Vajda.settings.setWearDelay * 1000)
Vajda.equipSet(job.set)
Manager.useBuff('character')
while (true) {
if ( TaskQueue.queue.length === 0 ) {
Vajda.updateStatistics(oldXp, oldMoney)
Vajda.setCookies()
Vajda.prepareJobRun(jobIndex)
return
}
if ( !Vajda.isRunning || Vajda.isHealthBelowLimit() ) {
break
}
await sleep(1000)
}
Vajda.statistics.sessionJobsCount -= TaskQueue.queue.length
Vajda.statistics.totalJobsCount -= TaskQueue.queue.length
Vajda.updateStatistics(oldXp, oldMoney)
Vajda.setCookies()
Vajda.cancelJobs()
if ( Vajda.isRunning && Vajda.isHealthBelowLimit() ) {
await sleep(2000)
Vajda.run()
}
}
Vajda.walkToJob = async function(index) {
const job = Vajda.addedJobs.at(index)
const jobGroup = JobList.getJobsByGroupId(job.groupId)
const jobToWalkTo = jobGroup.map(j =>
j.id
).map( id => {
const j = JobsModel.getById(id)
return {
id: id,
workpoints: j.workpoints, //required LP
jobpoints: j.jobpoints //character has LP
}
}).reduce((prev, curr) => {
return prev.workpoints < curr.workpoints ? prev : curr
})
await Manager.useBuff('travel')
if ( Vajda.isAllowedToDepositMoney() ) {
Observer.start()
await Vajda.goDepositMoney()
}
JobWindow.startJob(jobToWalkTo.id, job.x, job.y, 15)
Observer.start()
while (true) {
if ( GameMap.calcWayTime(Character.position, {x: job.x, y: job.y} ) === 0 ) {
break
}
if ( !Vajda.isRunning ) {
break
}
await sleep(1000)
}
Vajda.cancelJobs()
if ( Vajda.isRunning )
Vajda.prepareJobRun(index)
}
Vajda.prepareJobRun = async function(index) {
const job = Vajda.addedJobs.at(index)
setTimeout(function() {
Vajda.loadJobMotivation(index, async function(motivation) {
if ( Character.energy === 0 || Vajda.isHealthBelowLimit() ) {
Vajda.run()
} else if ( motivation <= job.stopMotivation && job.stopMotivation > 0 ) {
Vajda.checkMotivation(0, [], function(result) {
if ( Vajda.isMotivationAbove(result) ) {
Vajda.changeJob()
} else {
Vajda.run()
}
})
} else if ( GameMap.calcWayTime(Character.position,{x: job.x, y: job.y}) === 0 ) {
let maxJobs = Premium.hasBonus('automation') ? 9 : 4
let numberOfJobs
if (job.stopMotivation !== 0 ) {
numberOfJobs = Math.min(Math.min(motivation - job.stopMotivation, Character.energy), maxJobs)
} else {
numberOfJobs = Math.min(Character.energy, maxJobs)
}
Vajda.runJob(index, Math.floor(numberOfJobs))
if ( Manager.isOptimized )
Manager.checkSchedule(numberOfJobs)
} else {
await Vajda.equipSet(Vajda.travelSet)
Vajda.walkToJob(index)
}
})
}, Vajda.RNG(Vajda.settings.jobDelayMin, Vajda.settings.jobDelayMax) * 1000)
}
Vajda.canAddMissing = function(result) {
if ( !Vajda.settings.addMotivation && Vajda.jobsBelowMotivation(result) && !Vajda.isStopMotivationZero() ) {
alert("Can't continue because of motivation")
return false
}
if ( !Vajda.settings.addEnergy && Character.energy === 0 ) {
alert("Can't continue because of energy")
return false
}
if ( !Vajda.settings.addHealth && Vajda.isHealthBelowLimit() ) {
alert("Can't continue because of health")
return false
}
return true
}
Vajda.finishRun = function() {
Vajda.currentState = 0
Vajda.isRunning = false
Vajda.selectTab("chosenJobs")
alert("Finished")
}
Vajda.jobsBelowMotivation = function(result) {
let count = 0
for ( let i = 0; i < result.length; i++ ) {
if ( result[i] <= Vajda.addedJobs[i].stopMotivation ) {
count++
}
}
return count
}
Vajda.averageMissingMotivation = function(result) {
let motivation = 0
for ( let i = 0; i < result.length; i++ ) {
motivation += 100-result[i]
}
return motivation/result.length
}
Vajda.fillUp = async function(result) {
const energyMissing = 100 - (Character.energy/Character.maxEnergy) * 100
const motivationMissing = Vajda.jobsBelowMotivation(result)
const averageMotivationMissing = Vajda.averageMissingMotivation(result)
const consumableToUse = Manager.findProperConsumable(motivationMissing, energyMissing, averageMotivationMissing)
if ( consumableToUse === null ) return false
await Manager.useConsumableOrWaitForCooldown(consumableToUse, true)
if ( Manager.isOptimized && consumableToUse.isCakeDecoration() ) {
const updatedMotivation = Vajda.updateJobsMotivationOnRefill(consumableToUse.motivation)
await Manager.createSchedule(updatedMotivation)
}
return true
}
Vajda.updateStatistics = function(oldXp, oldMoney) {
const xpDiff = Character.experience - oldXp
const moneyDiff = Character.money - oldMoney
Vajda.statistics.sessionXpCount += xpDiff
Vajda.statistics.totalXpCount += xpDiff
if ( moneyDiff > 0 ) { //spending money while vajda is running would make this a bit funky
Vajda.statistics.sessionMoneyCount += moneyDiff
Vajda.statistics.totalMoneyCount += moneyDiff
}
}
Vajda.run = async function() {
Vajda.checkMotivation(0, [], async function(result) {
if ( ( Vajda.isMotivationAbove(result) || Vajda.isStopMotivationZero()) && Character.energy > 0 && !Vajda.isHealthBelowLimit() ) {
Vajda.currentState = 1
Vajda.selectTab("chosenJobs")
Vajda.prepareJobRun(Vajda.currentJob.job)
} else {
if ( !Vajda.canAddMissing(result) ) {
Vajda.finishRun()
} else {
let answer = await Vajda.fillUp(result)
if ( !answer ) {
Vajda.finishRun()
}
}
}
})
}
Vajda.formatNumber = function(number) {
if ( typeof number === 'number' ) {
number = String(number)
}
const numberString = number.replace(/[ ,]/g, '')
let formattedNumber = ''
for ( let i = 0; i < numberString. length; i++ ) {
if ( i > 0 && i % 3 === 0 ) {
formattedNumber = ' ' + formattedNumber
}
formattedNumber = numberString[numberString.length - 1 - i] + formattedNumber
}
return formattedNumber
}
Vajda.createConsumablesTable = function() {
let htmlSkel = $(`<div id='consumables_overview'></div>`)
let html = $(`
<div class ='consumables_filter' style='position: relative'>
<div id='energy_consumables' style='position: absolute; top: 10px; left: 15px'></div>
<div id='motivation_consumables' style='position: absolute; top: 10px; left: 160px'></div>
<div id='health_consumables' style='position: absolute; top: 10px; left: 320px'></div>
<div id='buff_consumables' style='position: absolute; top: 10px; left: 460px'></div>
</div>`
)
let table = new west.gui.Table()
let consumableList = Vajda.filterConsumables(Vajda.consumableSelection.energy, Vajda.consumableSelection.motivation, Vajda.consumableSelection.health, Vajda.consumableSelection.hideBuffs)
table.addColumn("consumIcon","consumIcon").addColumn("consumCount","consumCount").addColumn("consumEnergy","consumEnergy").addColumn("consumMotivation","consumMotivation").addColumn("consumHealth","consumHealth").addColumn("consumBuffs", "consumBuffs").addColumn("consumSelected","consumSelected")
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")
for ( const consumable of consumableList ) {
const checkbox = new west.gui.Checkbox()
checkbox.setSelected(consumable.isSelected)
checkbox.setId(consumable.id)
checkbox.setCallback(function() {
Vajda.consumableTablePosition.content = $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css("top")
Vajda.consumableTablePosition.scrollbar = $(".vajda-window .tw2gui_scrollbar_pulley").css("top")
if ( consumable instanceof Buff && !consumable.hasCooldown() ) {
Manager.selectedBuffs = consumable
Vajda.selectTab('consumables')
Vajda.setCookies()
return
}
Vajda.changeConsumableSelection(parseInt(this.divMain.attr("id")), this.isSelected())
Vajda.selectTab("consumables")
Vajda.setCookies()
})
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())
}
const buttonSelect = new west.gui.Button("Select all", function() {
Vajda.changeSelectionAllConsumables(true)
Vajda.selectTab("consumables")
Vajda.setCookies()
})
const buttonDeselect = new west.gui.Button("Deselect all", function() {
Vajda.changeSelectionAllConsumables(false)
Vajda.selectTab("consumables")
Vajda.setCookies()
})
table.appendToFooter("consumEnergy",buttonSelect.getMainDiv())
table.appendToFooter("consumHealth",buttonDeselect.getMainDiv())
htmlSkel.append(table.getMainDiv())
const checkboxEnergyConsumes = new west.gui.Checkbox()
checkboxEnergyConsumes.setLabel("Energy consumables")
checkboxEnergyConsumes.setSelected(Vajda.consumableSelection.energy)
checkboxEnergyConsumes.setCallback(function() {
Vajda.consumableSelection.energy = this.isSelected()
Vajda.selectTab("consumables")
})
const checkboxMotivationConsumes = new west.gui.Checkbox()
checkboxMotivationConsumes.setLabel("Motivation consumables")
checkboxMotivationConsumes.setSelected(this.consumableSelection.motivation)
checkboxMotivationConsumes.setCallback(function() {
Vajda.consumableSelection.motivation = this.isSelected()
Vajda.selectTab("consumables")
})
const checkboxHealthConsumes = new west.gui.Checkbox()
checkboxHealthConsumes.setLabel("Health consumables")
checkboxHealthConsumes.setSelected(this.consumableSelection.health)
checkboxHealthConsumes.setCallback(function() {
Vajda.consumableSelection.health = this.isSelected()
Vajda.selectTab("consumables")
})
const buffsFilter = new west.gui.Checkbox()
buffsFilter.setLabel("Hide buffs")
buffsFilter.setSelected(this.consumableSelection.hideBuffs)
buffsFilter.setCallback(function() {
Vajda.consumableSelection.hideBuffs = this.isSelected()
Vajda.selectTab("consumables")
})
$("#energy_consumables", html).append(checkboxEnergyConsumes.getMainDiv())
$("#motivation_consumables", html).append(checkboxMotivationConsumes.getMainDiv())
$("#health_consumables", html).append(checkboxHealthConsumes.getMainDiv())
$("#buff_consumables", html).append(buffsFilter.getMainDiv())
htmlSkel.append(html)
return htmlSkel
}
Vajda.createAddedJobsTab = function() {
const htmlSkel = $(`<div id='added_jobs_overview'></div>`)
const footerHtml = $(`
<div id='start_vajda' style='position: relative'>
<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;'>
Current state: ${Vajda.states[Vajda.currentState]}
</span>
<div class='vajda_run' style='position: absolute; left: 350px; top: 20px'></div>
</div>
`)
const table = new west.gui.Table()
table.addColumn("jobIcon","jobIcon").addColumn("jobName","jobName").addColumn("jobStopMotivation","jobStopMotivation").addColumn("jobSet","jobSet").addColumn("jobRemove","jobRemove")
table.appendToCell("head","jobIcon","Job icon").appendToCell("head","jobName","Job name").appendToCell("head","jobStopMotivation","Stop motivation").appendToCell("head","jobSet","Job set").appendToCell("head","jobRemove","")
for ( let job = 0; job < Vajda.addedJobs.length; job++ ) {
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))
}
const buttonStart = new west.gui.Button("Start", async function() {
const parseSuccesful = Vajda.parseStopMotivation()
if ( parseSuccesful ) {
Vajda.currentState = 3
$(`#vajda-state-info`).text(`Current state: ${Vajda.states[3]}`)
Vajda.createRoute()
Vajda.isRunning = true
Vajda.setCookies()
if ( Manager.isOptimized && Manager.hasEnoughPlugsAndDecorations() ) {
await Manager.createSchedule()
}
Observer.start()
Vajda.run()
} else {
new UserMessage("Wrong format of set stop motivation", UserMessage.TYPE_ERROR).show()
}
});
const buttonStop = new west.gui.Button("Stop",function() {
Vajda.isRunning = false
Vajda.currentState = 0
Vajda.selectTab("chosenJobs")
Observer.stop()
})
htmlSkel.append(table.getMainDiv())
$(".vajda_run",footerHtml).append(buttonStart.getMainDiv())
$(".vajda_run",footerHtml).append(buttonStop.getMainDiv())
htmlSkel.append(footerHtml)
return htmlSkel
}
Vajda.createStatisticsGui = function() {
const offsetLeft = '.5rem'
const statsBubbleStyle = `'
padding: 1rem 2rem;
border-radius: 10px;
background-color: rgba(255, 255, 228, .3);
position: relative;
box-shadow: 0 0 5px rgba(0, 0, 0, .2)
'`
const pseudoHeadingStyle = `'
display: block;
width: calc(100% - ${offsetLeft});
padding-left: ${offsetLeft};
border-bottom: 1px solid black;
margin-bottom: .5rem
'`
const refreshStats = `
<div style=${statsBubbleStyle}>
<b style=${pseudoHeadingStyle}>REFRESH COUNT</b>
<p style='padding-left:${offsetLeft}'>Total in this session: ${Observer.refreshCount}</p>
</div>
`
return $(`
<div id='statistics_overview' style='padding: 0 2rem; display: grid; gap: 1rem'>
<div style=${statsBubbleStyle}>
<b style=${pseudoHeadingStyle}>EXPERIENCE</b>
<p style='padding-left: ${offsetLeft}'>Total in this session: ${Vajda.formatNumber(Vajda.statistics.sessionXpCount)}</p>
<p style='padding-left: ${offsetLeft}'>Total overall: ${Vajda.formatNumber(Vajda.statistics.totalXpCount)}</p>
</div>
<div style=${statsBubbleStyle}>
<b style=${pseudoHeadingStyle}>MONEY</b>
<p style='padding-left: ${offsetLeft}'>Total in this session: ${Vajda.formatNumber(Vajda.statistics.sessionMoneyCount)}</p>
<p style='padding-left: ${offsetLeft}'>Total overall: ${Vajda.formatNumber(Vajda.statistics.totalMoneyCount)}</p>
</div>
<div style=${statsBubbleStyle}>
<b style=${pseudoHeadingStyle}>JOBS</b>
<p style='padding-left: ${offsetLeft}'>Total in this session: ${Vajda.formatNumber(Vajda.statistics.sessionJobsCount)}</p>
<p style='padding-left: ${offsetLeft}'>Total overall: ${Vajda.formatNumber(Vajda.statistics.totalJobsCount)}</p>
</div>
${Observer.isEnabled ? refreshStats : ''}
</div>
`)
}
Vajda.createSettingsGui = function() {
const htmlSkel = $(`<div id='settings_overview' style='padding: 10px'></div>`)
const checkboxAddEnergy = new west.gui.Checkbox()
checkboxAddEnergy.setLabel("Add energy")
checkboxAddEnergy.setSelected(Vajda.settings.addEnergy)
checkboxAddEnergy.setCallback(function() {
Vajda.settings.addEnergy = !Vajda.settings.addEnergy
})
const checkboxAddMotivation = new west.gui.Checkbox()
checkboxAddMotivation.setLabel("Add motivation")
checkboxAddMotivation.setSelected(Vajda.settings.addMotivation)
checkboxAddMotivation.setCallback(function() {
Vajda.settings.addMotivation = !Vajda.settings.addMotivation
})
const checkboxAddHealth = new west.gui.Checkbox()
checkboxAddHealth.setLabel("Add health")
checkboxAddHealth.setSelected(Vajda.settings.addHealth)
checkboxAddHealth.setCallback(function() {
Vajda.settings.addHealth = !Vajda.settings.addHealth
})
const buttPlugsCheckbox = new west.gui.Checkbox()
buttPlugsCheckbox.setLabel('Optimize for butt plugs and cake decorations')
buttPlugsCheckbox.setSelected(Manager.isOptimized)
buttPlugsCheckbox.setCallback(() => {
Manager.isOptimized = p => !p
})
const enableObserverCheckbox = new west.gui.Checkbox()
enableObserverCheckbox.setLabel('[Experimental] Enable auto refresh → Read user manual')
enableObserverCheckbox.setSelected(Observer.isEnabled)
enableObserverCheckbox.setCallback(() => {
Observer.isEnabled = previous => {
$('#observer-delay-input').css('max-height', previous ? '0px' : '30px')
Vajda.isRunning && !previous && Observer.start(forceStart = true)
Vajda.isRunning && previous && Observer.stop()
return !previous
}
})
const observerDelayInput = new west.gui.Textfield()
observerDelayInput.setWidth(100)
observerDelayInput.setValue(Observer.getTimeOut(true))
observerDelayInput.getMainDiv()[0].querySelector('input').addEventListener('change', e => {
const val = e.target.value
if ( Vajda.isNumber(val) ) {
Observer.timeOut = val
}
})
const style = (isOpen) => `'
overflow: hidden;
max-height: ${isOpen ? '30' : '0'}px;
transition: max-height .5s;
margin-bottom: 1rem;
'`
const observerDelay = $(`
<div style=${style(Observer.isEnabled)} id='observer-delay-input'>
Refresh page after
</div>
`)
observerDelay.append(observerDelayInput.getMainDiv())
observerDelay.append(` minutes since the last action`)
const saveMoneyCheckbox = new west.gui.Checkbox()
saveMoneyCheckbox.setLabel('Deposit money in your hometown')
saveMoneyCheckbox.setSelected(Vajda.settings.addDeposit.isEnabled)
saveMoneyCheckbox.setCallback(() => {
if ( Character.homeTown.town_id === 0 ) {
new UserMessage("You don' have a home town", UserMessage.TYPE_HINT).show()
return
}
const oldVal = !!Vajda.settings.addDeposit.isEnabled
Vajda.settings.addDeposit.isEnabled = !oldVal
$(`#deposit-limit-input`).css('max-height', oldVal ? '0px' : '30px')
})
const depositLimit = $(`
<div style=${style(Vajda.settings.addDeposit.isEnabled)} id='deposit-limit-input'>
Deposit when more than
</div>
`)
const limitInput = new west.gui.Textfield()
limitInput.setWidth(100)
limitInput.setValue(Number.isNaN(Vajda.settings.addDeposit.limit) ? '' : Vajda.settings.addDeposit.limit)
limitInput.getMainDiv()[0].querySelector('input').addEventListener('change', e => {
const val = e.target.value
if ( Vajda.isNumber(val) ) {
Vajda.settings.addDeposit.limit = val
}
})
depositLimit.append(limitInput.getMainDiv())
depositLimit.append(` $ in cash`)
const htmlHealthStop = $("<div></div>")
htmlHealthStop.append(`<span>Stoppage health percent value</span>`)
const healthStopTextfiled = new west.gui.Textfield("healthStop")
healthStopTextfiled.setValue(Vajda.settings.healthStop)
healthStopTextfiled.setWidth(100)
htmlHealthStop.append(healthStopTextfiled.getMainDiv())
const htmlSetWearDelay = $("<div></div>")
htmlSetWearDelay.append("<span> Job set equip delay </span>")
const setWearDelayTextfiled = new west.gui.Textfield("setWearDelay")
setWearDelayTextfiled.setValue(Vajda.settings.setWearDelay)
setWearDelayTextfiled.setWidth(100)
htmlSetWearDelay.append(setWearDelayTextfiled.getMainDiv())
const htmlJobDelay = $("<div></div>")
htmlJobDelay.append(`<span>Random delay between jobs(seconds)</span>`)
const jobDelayTextFieldMin = new west.gui.Textfield("jobDelay")
jobDelayTextFieldMin.setValue(Vajda.settings.jobDelayMin)
jobDelayTextFieldMin.setWidth(50)
const jobDelayTextFieldMax = new west.gui.Textfield("jobDelay")
jobDelayTextFieldMax.setValue(Vajda.settings.jobDelayMax)
jobDelayTextFieldMax.setWidth(50)
htmlJobDelay.append(jobDelayTextFieldMin.getMainDiv())
htmlJobDelay.append("<span> - </span>")
htmlJobDelay.append(jobDelayTextFieldMax.getMainDiv())
const manualLink = `
<div onclick=Vajda.selectTab('manual') style="cursor: pointer; text-decoration: underline; position: absolute; top: 20px; right: 25px;">
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>
</div>
`
const buttonApply = new west.gui.Button("Apply", function() {
Vajda.settings.addEnergy = checkboxAddEnergy.isSelected()
Vajda.settings.addMotivation = checkboxAddMotivation.isSelected()
Vajda.settings.addHealth = checkboxAddHealth.isSelected()
if ( Vajda.isNumber(healthStopTextfiled.getValue()) ) {
let healthStop = parseInt(healthStopTextfiled.getValue())
healthStop = Math.min(30,healthStop)
Vajda.settings.healthStop = healthStop
}
if ( Vajda.isNumber(setWearDelayTextfiled.getValue()) ) {
let setWearDelay = parseInt(setWearDelayTextfiled.getValue())
setWearDelay = Math.min(10,setWearDelay)
Vajda.settings.setWearDelay = setWearDelay
}
if ( Vajda.isNumber(jobDelayTextFieldMin.getValue()) ) {
let jobDelayTimeMin = parseInt(jobDelayTextFieldMin.getValue())
Vajda.settings.jobDelayMin = jobDelayTimeMin
} else {
Vajda.settings.jobDelayMin = 0
Vajda.settings.jobDelayMax = 0
new UserMessage("Wrong format of delay job min value. Please set a number.", UserMessage.TYPE_ERROR).show()
}
if ( Vajda.isNumber(jobDelayTextFieldMax.getValue()) ) {
let jobDelayTimeMax = parseInt(jobDelayTextFieldMax.getValue())
Vajda.settings.jobDelayMax = jobDelayTimeMax
} else {
Vajda.settings.jobDelayMin = 0
Vajda.settings.jobDelayMax = 0
new UserMessage("Wrong format of delay job max value. Please set a number.", UserMessage.TYPE_ERROR).show()
}
Vajda.setCookies()
Vajda.selectTab("settings")
})
htmlSkel.append(manualLink)
htmlSkel.append(checkboxAddEnergy.getMainDiv())
htmlSkel.append("<br>")
htmlSkel.append(checkboxAddMotivation.getMainDiv())
htmlSkel.append("<br>")
htmlSkel.append(checkboxAddHealth.getMainDiv())
htmlSkel.append("<br>")
htmlSkel.append(buttPlugsCheckbox.getMainDiv())
htmlSkel.append("<br>")
htmlSkel.append(enableObserverCheckbox.getMainDiv())
htmlSkel.append("<br>")
htmlSkel.append(observerDelay)
htmlSkel.append(saveMoneyCheckbox.getMainDiv())
htmlSkel.append(depositLimit)
htmlSkel.append(htmlHealthStop)
htmlSkel.append("<br>")
htmlSkel.append(htmlSetWearDelay)
htmlSkel.append("<br>")
htmlSkel.append(htmlJobDelay)
htmlSkel.append("<br>")
htmlSkel.append(buttonApply.getMainDiv())
return htmlSkel
}
Vajda.createManualGui = function() {
const listStyle = `'padding-inline-start: 14px'`
const nestedListStyle = `'padding-inline-start: 30px'`
const containerStyle = `'
padding: 0 30px 30px
'`
const html = `
<div style=${containerStyle}>
<h3>Read Before use</h3>
<ol style=${listStyle}>
<li>
<strong>Calculating optimal route</strong> takes time and memory, a lot of it. It might not be noticeable for up to 12-14 jobs,
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
algorithm will take about a minute (depending on the hardware, of course) to execute, while it takes almost 8 minutes to
find the best route for 20 jobs. In these scenarios, your browser may appear unresponsive and prompt you to reload the page
or wait. I recommend being patient and allowing some time for the algorithm to complete. If that doesn't work, remove one
or two jobs; that's the cheapest way to solve this problem.
</li>
<li>
<strong>The optimization for butt plugs and cake decorations</strong> setting, which is most likely why you are here:
<ul style=${nestedListStyle}>
<li>The setting has to be enabled <i>before</i> you start Zdenka, it won't work otherwise</li>
<li>The <i>Add motivation</i> setting has to be enabled as well</li>
<li>Do not start Zdenka with low energy and consumables on cooldown</li>
<li>Do not use consumables yourself while it's running</li>
<li>
You don't have to select consumables manually with this setting, Zdenka will do it for you. Just make sure
you have enough of them butt plugs and decorations
</li>
</ul>
These restrictions are simply the cost of having Zdenka refill energy <i>while</i> doing jobs.
</li>
<li>
Zdenka can <strong>travel</strong> to jobs that you can't do in travel set (unless you are super low level).
</li>
<li>
<strong>Buffs</strong> will be used automatically when selected (and when no buff is active, of course). Only one buff
of each type can be selected at once. Keep in mind that consumables with cooldown are <b>not</b> treated as buffs and will
only be used to refill whatever your character needs.
</li>
<li>
Zdenka will display <strong>all silver jobs</strong>, not just those you can do and are closest to yoor character. This
allows you <i>some</i> control of the route, for instance there might be multiple silver jobs of the same kind and one
of them might simply be in a more advantageous position.
</li>
<li>
When <strong>Auto Refresh</strong> is enabled, Zdenka will refresh the page and start automatically <i>n</i> minutes
after starting a job (or walking to one). Starting new jobs will restart this countdown. Do not set the delay to low numbers,
Zdenka enforces a minimum of 2.5 minutes anyway, however, I do recommend a slightly longer delay.
</li>
</ol>
</div>
`
const container = new west.gui.Scrollpane().getMainDiv()
container.style = 'height: 400px; overflow-y: scroll'
container.innerHTML = html
return container
}
Vajda.createMenuIcon = function() {
const menuImage = 'data:image/jpeg;base64,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'
let div = $('<div class="ui_menucontainer" />')
let link = $('<div id="vajda_menu" class="menulink" onclick=Vajda.loadJobs() title="Zdenka Studenková" />').css('background-image', 'url(' + menuImage + ')')
$('#ui_menubar').append((div).append(link).append('<div class="menucontainer_bottom" />'))
}
Vajda.createWindow = function(isHumanAction = true) {
const window = wman.open("vajda").setResizeable(false).setMinSize(650, 480).setSize(650, 480).setMiniTitle("Vajda Jožo")
const tabs = {
"jobs": "Jobs",
"chosenJobs": "Chosen Jobs",
"sets": "Sets",
"consumables": "Consumables",
"stats": "Statistics",
"settings": "Settings",
"manual": "User manual"
}
let tabLogic = function(win,id) {
const content = $(`<div class='vajda-window'></div>`)
switch(id) {
case 'jobs':
Vajda.loadJobData(function(){
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("jobs",this)
content.append(Vajda.createJobsTab())
Vajda.window.appendToContentPane(content)
Vajda.addJobTableCss()
$(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css({"top": Vajda.jobTablePosition.content})
$(".vajda-window .tw2gui_scrollbar_pulley").css({"top": Vajda.jobTablePosition.scrollbar})
Vajda.addEventsHeader()
})
break
case 'chosenJobs':
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("chosenJobs", this)
content.append(Vajda.createAddedJobsTab())
Vajda.window.appendToContentPane(content)
$(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css({"top": Vajda.addedJobTablePosition.content})
$(".vajda-window .tw2gui_scrollbar_pulley").css({"top": Vajda.addedJobTablePosition.scrollbar})
Vajda.addAddedJobsTableCss()
break
case 'sets':
Vajda.loadSets(function() {
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("sets",this)
content.append(Vajda.createSetGui())
Vajda.window.appendToContentPane(content)
})
break
case 'consumables':
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("consumables",this)
Vajda.findAllConsumables()
content.append(Vajda.createConsumablesTable())
Vajda.window.appendToContentPane(content)
$(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css({"top": Vajda.consumableTablePosition.content})
$(".vajda-window .tw2gui_scrollbar_pulley").css({"top": Vajda.consumableTablePosition.scrollbar})
Vajda.addConsumableTableCss()
break
case 'stats':
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("stats",this)
content.append(Vajda.createStatisticsGui())
Vajda.window.appendToContentPane(content)
break
case 'settings':
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("settings",this)
content.append(Vajda.createSettingsGui())
Vajda.window.appendToContentPane(content)
break
case 'manual':
Vajda.removeActiveTab(this)
Vajda.removeWindowContent()
Vajda.addActiveTab("manual", this)
content.append(Vajda.createManualGui())
Vajda.window.appendToContentPane(content)
break
}
}
for(let tab in tabs) {
window.addTab(tabs[tab],tab,tabLogic)
}
Vajda.window = window
if ( !isHumanAction ) wman.close('vajda')
Vajda.selectTab('jobs')
}
Vajda.selectTab = function(key) {
Vajda.window.tabIds[key].f(Vajda.window,key)
}
Vajda.removeActiveTab = function(window) {
$('div.tw2gui_window_tab', window.divMain).removeClass('tw2gui_window_tab_active')
}
Vajda.addActiveTab = function(key, window) {
$(`div._tab_id_${key}`, window.divMain).addClass('tw2gui_window_tab_active')
}
Vajda.removeWindowContent = function() {
$(".vajda-window").remove()
}
Vajda.addConsumableTableCss = function() {
$(".vajda-window .consumIcon").css({"width":"80px"})
$(".vajda-window .consumCount").css({"width":"60px"})
$(".vajda-window .consumEnergy").css({"width":"60px"})
$(".vajda-window .consumMotivation").css({"width":"70px"})
$(".vajda-window .consumHealth").css({"width":"60px"})
$(".vajda-window .consumBuffs").css({"width": "150px"})
$(".vajda-window .row").css({"height":"80px"})
$('.vajda-window').find('.tw2gui_scrollpane').css('height', '250px')
}
Vajda.addJobTableCss = function() {
$(".vajda-window .jobIcon").css({"width":"80px"})
$(".vajda-window .jobName").css({"width":"150px"})
$(".vajda-window .jobXp").css({"width":"40px"})
$(".vajda-window .jobMoney").css({"width":"40px"})
$(".vajda-window .jobMotivation").css({"width":"40px"})
$(".vajda-window .jobDistance").css({"width":"100px"})
$(".vajda-window .row").css({"height":"60px"})
$('.vajda-window').find('.tw2gui_scrollpane').css('height', '250px')
}
Vajda.addAddedJobsTableCss = function() {
$(".vajda-window .jobIcon").css({"width":"80px"})
$(".vajda-window .jobName").css({"width":"130px"})
$(".vajda-window .jobStopMotivation").css({"width":"110px"})
$(".vajda-window .jobRemove").css({"width":"105px"})
$(".vajda-window .jobSet").css({"width":"100px"})
$(".vajda-window .row").css({"height":"60px"})
$('.vajda-window').find('.tw2gui_scrollpane').css('height', '250px')
}
Vajda.createJobsTab = function() {
const htmlSkel = $(`<div id='jobs_overview'></div>`)
const html = $(`
<div class='jobs_search' style='position: relative'>
<div id='jobFilter' style='position: absolute; top: 10px; left: 15px'></div>
<div id='job_only_silver' style='position: absolute; top:10px; left: 200px;'></div>
<div id='job_no_silver' style='position: absolute; top: 10px; left: 270px;'></div>
<div id='job_center' style='position: absolute; top: 10px; left: 350px;'></div>
<div id='button_filter_jobs' style='position: absolute; top: 5px; left: 450px;'></div>
</div>
`)
const table = new west.gui.Table()
const xpIcon = '<img src="/images/icons/star.png">'
const dollarIcon = '<img src="/images/icons/dollar.png">'
const motivationIcon = '<img src="/images/icons/motivation.png">'
const arrow_desc = ' <img src="../images/window/jobs/sortarrow_desc.png"/>'
const arrow_asc = ' <img src="../images/window/jobs/sortarrow_asc.png"/>'
const uniqueJobs = Vajda.getAllUniqueJobs()
table
.addColumn("jobIcon","jobIcon")
.addColumn("jobName","jobName")
.addColumn("jobXp","jobXp")
.addColumn("jobMoney","jobMoney")
.addColumn("jobMotivation","jobMotivation")
.addColumn("jobDistance","jobDistance")
.addColumn("jobAdd","jobAdd")
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","")
for ( let job = 0; job < uniqueJobs.length; job++ ) {
table
.appendRow()
.appendToCell(-1,"jobIcon",Vajda.getJobIcon(uniqueJobs[job].isSilver,uniqueJobs[job].id,uniqueJobs[job].x,uniqueJobs[job].y))
.appendToCell(-1,"jobName",Vajda.getJobName(uniqueJobs[job].id))
.appendToCell(-1,"jobXp",uniqueJobs[job].experience)
.appendToCell(-1,"jobMoney",uniqueJobs[job].money)
.appendToCell(-1,"jobMotivation",uniqueJobs[job].motivation)
.appendToCell(-1,"jobDistance",uniqueJobs[job].distance.formatDuration())
.appendToCell(-1,"jobAdd", Vajda.createAddJobButton(uniqueJobs[job].x,uniqueJobs[job].y,uniqueJobs[job].id))
}
const textfield = new west.gui.Textfield("jobsearch").setPlaceholder("Select job name")
if ( Vajda.jobFilter.filterJob !== "" ) {
textfield.setValue(Vajda.jobFilter.filterJob)
}
const checkboxOnlySilver = new west.gui.Checkbox()
checkboxOnlySilver.setLabel("Silvers")
checkboxOnlySilver.setSelected(Vajda.jobFilter.filterOnlySilver)
checkboxOnlySilver.setCallback(function() {
if ( this.isSelected() ) {
Vajda.jobFilter.filterOnlySilver = true
}else {
Vajda.jobFilter.filterOnlySilver = false
}
})
const checkboxNoSilver = new west.gui.Checkbox()
checkboxNoSilver.setLabel("No silvers")
checkboxNoSilver.setSelected(Vajda.jobFilter.filterNoSilver)
checkboxNoSilver.setCallback(function() {
if ( this.isSelected() ) {
Vajda.jobFilter.filterNoSilver = true
} else {
Vajda.jobFilter.filterNoSilver = false
}
})
const checkboxCenterJobs = new west.gui.Checkbox()
checkboxCenterJobs.setLabel("Center jobs")
checkboxCenterJobs.setSelected(Vajda.jobFilter.filterCenterJobs)
checkboxCenterJobs.setCallback(function() {
if ( this.isSelected() ) {
Vajda.jobFilter.filterCenterJobs = true
} else {
Vajda.jobFilter.filterCenterJobs = false
}
})
const buttonFilter = new west.gui.Button("Filter", function() {
Vajda.jobFilter.filterJob = textfield.getValue()
Vajda.jobTablePosition.content = "0px"
Vajda.jobTablePosition.scrollbar = "0px"
Vajda.selectTab("jobs")
})
htmlSkel.append(table.getMainDiv())
$('#jobFilter', html).append(textfield.getMainDiv())
$("#job_only_silver",html).append(checkboxOnlySilver.getMainDiv())
$("#job_no_silver",html).append(checkboxNoSilver.getMainDiv())
$("#job_center",html).append(checkboxCenterJobs.getMainDiv())
$("#button_filter_jobs",html).append(buttonFilter.getMainDiv())
htmlSkel.append(html)
return htmlSkel
}
Vajda.createAddJobButton = function(x, y, id) {
const buttonAdd = new west.gui.Button("Add new job", function() {
Vajda.addJob(x, y, id)
Vajda.jobTablePosition.content = $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css("top")
Vajda.jobTablePosition.scrollbar = $(".vajda-window .tw2gui_scrollbar_pulley").css("top")
Vajda.selectTab("jobs")
})
buttonAdd.setWidth(100)
return buttonAdd.getMainDiv()
}
Vajda.createMinMotivationTextfield = function(x, y, id, placeholder) {
const componentId = `x-${x}y-${y}id-${id}`
const textfield = new west.gui.Textfield()
textfield.setId(componentId)
textfield.setWidth(40)
textfield.setValue(placeholder)
return textfield.getMainDiv()
}
Vajda.createRemoveJobButton = function(x, y, id) {
const buttonRemove = new west.gui.Button("Remove job", function() {
Vajda.removeJob(x, y, id)
Vajda.addedJobTablePosition.content = $(".vajda-window .tw2gui_scrollpane_clipper_contentpane").css("top")
Vajda.addedJobTablePosition.scrollbar = $(".vajda-window .tw2gui_scrollbar_pulley").css("top")
Vajda.selectTab("chosenJobs")
})
buttonRemove.setWidth(100)
return buttonRemove.getMainDiv()
}
$(document).ready(() => {
try {
Vajda.loadLanguage()
Vajda.loadSets()
Vajda.createMenuIcon()
Vajda.getCookies()
Observer.resumeSession()
} catch(e) {
console.log(e)
console.log("exception occured")
}
})
})()