您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Bloop Bleep. I am a robot.
// ==UserScript== // @name Melvor Golbin Raider // @namespace http://tampermonkey.net/ // @version 0.1.5 // @description Bloop Bleep. I am a robot. // @author NotCorgan#1234 // @match https://melvoridle.com/* // @match https://www.melvoridle.com/* // @match https://test.melvoridle.com/* // @exclude https://melvoridle.com/update/* // @exclude https://www.melvoridle.com/update/* // @exclude https://test.melvoridle.com/update/* // @grant none // @noframes // ==/UserScript== /* jshint esversion: 6 */ // Made for version 1.0.2 (function () { function injectScript(main) { var script = document.createElement('script'); script.textContent = `try {(${main})();} catch (e) {console.log(e);}`; document.body.appendChild(script).parentNode.removeChild(script); } function script() { // Loading script /* RaidManager.difficulties[3] = { coinMultiplier: 1.5, combatTriangle: 1, enemyAccuracyModifier: 10, enemyEvasionModifier: 10, enemyHPModifier: 25, enemyMaxHitModifier: 10, hasSecondPassiveChange: true, name: "Chaos", negativeModifierCount: 10, positiveModifierCount: 5, selectedClass: "btn-info", unselectedClass: "btn-outline-info", } RaidDifficulty[3] = 'Chaos'; RaidDifficulty['Chaos'] = 3; $('#raid-difficulty-btn-2').after(` <button class="btn btn-outline-info w-25" type="button" id="raid-difficulty-btn-3" onclick="raidManager.changeDifficulty(3);"> <span>Chaos</span> </button> `); */ let defaultSteps = [ { "result": "weapons", "conditional": "wave", "comparison": "equals", "num": "1" }, { "result": "armour", "conditional": "wave", "comparison": "equals", "num": 2 }, { "result": "food", "conditional": "wave", "comparison": "equals", "num": 3 }, { "conditional": "and", "result": "passive", "num": "0", "mod": "5", "conditions": [ { "conditional": "wave", "comparison": "mod", "num": 0, "mod": "5" }, { "conditional": "equipment", "slot": 11, "type": "prio", "comparison": "greater-than", "num": "1" } ] }, { "result": "weapons", "conditional": "and", "conditions": [ { "conditional": "wave", "comparison": "greater-than-equals", "num": 4 }, { "conditional": "equipment", "comparison": "in", "slot": 4, "collection": [ { "num": -1 }, { "num": 436 }, { "num": 431 } ], "type": "item" } ] }, { "result": "food", "conditional": "food", "comparison": "less-than", "type": "total", "num": 800 }, { "result": "runes", "conditional": "and", "conditions": [ { "conditional": "or", "conditions": [ { "conditional": "rune", "comparison": "less-than", "type": 389, "num": "500" }, { "conditional": "rune", "comparison": "less-than", "type": 393, "num": "500" }, { "conditional": "rune", "type": 390, "comparison": "less-than", "num": "500" } ] }, { "conditional": "wave", "comparison": "greater-than-equals", "num": "4" } ] }, { "conditional": "and", "result": "armour", "conditions": [ { "conditional": "stats", "type": "damage-reduction", "comparison": "less-than", "num": "20" }, { "conditional": "wave", "comparison": "less-than", "num": "20" } ] }, { "conditional": "and", "result": "weapons", "conditions": [ { "conditional": "equipment", "slot": 4, "comparison": "not-equals", "type": "item", "num": 932 }, { "conditional": "wave", "comparison": "greater-than", "num": "20" } ] }, { "conditional": "and", "result": "runes", "conditions": [ { "conditional": "equipment", "slot": 4, "comparison": "equals", "num": 932, "type": "item" }, { "conditional": "or", "conditions": [ { "conditional": "rune", "type": 394, "comparison": "less-than", "num": "500" }, { "conditional": "rune", "type": 822, "comparison": "less-than", "num": "500" }, { "conditional": "rune", "type": 392, "comparison": "less-than", "num": "500" }, { "conditional": "rune", "type": 820, "comparison": "less-than", "num": "500" } ] } ] }, { "conditional": "or", "result": "armour", "conditions": [ { "conditional": "equipment", "slot": 0, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 1, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 2, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 3, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 6, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 7, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 8, "type": "prio", "comparison": "greater-than", "num": "2" }, { "conditional": "equipment", "slot": 10, "type": "prio", "comparison": "greater-than", "num": "2" } ] }, { "result": "runes", "conditional": "default" } ]; let golbinRaiderSelectionSteps = JSON.parse(localStorage.getItem(`golbinRaiderSelectionSteps`)||JSON.stringify(defaultSteps)) window.golbinRaiderSelectionSteps = golbinRaiderSelectionSteps; let prioritiesList = [ CONSTANTS.equipmentSlot.Weapon, CONSTANTS.equipmentSlot.Shield, CONSTANTS.equipmentSlot.Helmet, CONSTANTS.equipmentSlot.Platebody, CONSTANTS.equipmentSlot.Gloves, CONSTANTS.equipmentSlot.Platelegs, CONSTANTS.equipmentSlot.Boots, CONSTANTS.equipmentSlot.Cape, CONSTANTS.equipmentSlot.Amulet, CONSTANTS.equipmentSlot.Ring, CONSTANTS.equipmentSlot.Quiver, CONSTANTS.equipmentSlot.Passive]; let defaultPriorities = { "Weapon":[932,1200,930,1199,928,499,497], "Shield":[812,1114,1226], "Helmet":[1225,1214,718,713,776,781], "Platebody":[1216,720,715,778,783], "Gloves":[1147,722,717,780,785], "Platelegs":[719,714,777,782], "Boots":[1213,721,716,779,784], "Cape":[941,818,361], "Amulet":[819,795,793], "Ring":[1146,794,1115,792,1144,1148], "Quiver":[1083], "Passive":[1115,1114,795] }; let golbinRaiderPriorities = JSON.parse(localStorage.getItem(`golbinRaiderPriorities`)||JSON.stringify(defaultPriorities)) window.golbinRaiderPriorities = golbinRaiderPriorities; let golbinRaiderSettings = JSON.parse(localStorage.getItem(`golbinRaiderSettings`)||JSON.stringify({ autoHeal: true })) window.golbinRaiderSettings = golbinRaiderSettings; let golbinRaiderModifierPriority = JSON.parse(localStorage.getItem(`golbinRaiderModifierPriority`)||JSON.stringify({ positive: [...RaidManager.possibleModifiers].map(mod => ({key: mod.key, soft: 0, hard: 0 })), negative: [...RaidManager.possibleModifiers].map(mod => ({key: mod.key, soft: 0, hard: 0 })) })); window.golbinRaiderModifierPriority = golbinRaiderModifierPriority; /* TODO Item Selection Revamp (customizable weighting?) Ammo Selection Rune Selection Settings (???) autoHeal Allow 2H Allow Magic Allow Ranged */ let golbinRaidResults = { weapons: { id: "weapons", name: "Weapons" }, armour: { id: "armour", name: "Armor" }, food: { id: "food", name: "Food" }, runes: { id: "runes", name: "Runes" }, ammo: { id: "ammo", name: "Ammo" }, passive: { id: "passive", name: "Passive" }, pause: { id: "pause", name: "Pause Run" }, abort: { id: "abort", name: "Abort Run" } }; let golbinItemCount = id => raidManager.bank.getQty(id) let haveRunes = runes => runes.reduce((bool, rune) => bool && golbinItemCount(rune[0]) >= rune[1], true) let availableRunes = () => items.filter(item => item.type === "Rune" && !RaidManager.bannedItems.includes(item.id)).map(item => item.id); let combatLevel = (item) => { if(item.equipRequirements == undefined || item.equipRequirements.length == 0) return 0; return item.equipRequirements.filter(er => er.type == "Level").map(er => { return Math.max(...er.levels.filter(l => { return [6,7,8,12,16].includes(l.skill) }).map(l => l.level)); })[0]; } let hasOceanSong = () => raidManager.player.availableAttacks.map(aa => aa.attack.id).indexOf(31) != -1 const camel2title = (camelCase) => camelCase.replace(/([A-Z])/g, (match) => ` ${match}`).replace(/^./, (match) => match.toUpperCase()).trim(); const golbinRaidValues = { 'num': { id: 'num', name: 'Value', type: 'number', default: 0 }, 'mod': { id: 'mod', name: 'Mod', type: 'number', default: 0 } } const golbinRaidComparisons = { 'true': { id: 'true', name: "Is True", fn: (a) => a == true, values: () => [], }, 'false': { id: 'false', name: "Is False", fn: (a) => a == false, values: () => [], }, 'equals': { id: 'equals', name: "==", fn: (a, {num}) => a == num, values: () => [ golbinRaidValues['num'] ], }, 'not-equals': { id: 'not-equals', name: "!=", fn: (a, {num}) => a != num, values: () => [ golbinRaidValues['num'] ], }, 'less-than': { id: 'less-than', name: "<", fn: (a, {num}) => a < num, values: () => [ golbinRaidValues['num'] ], }, 'less-than-equals': { id: 'less-than-equals', name: "<=", fn: (a, {num}) => a <= num, values: () => [ golbinRaidValues['num'] ], }, 'greater-than': { id: 'greater-than', name: ">", fn: (a, {num}) => a > num, values: () => [ golbinRaidValues['num'] ], }, 'greater-than-equals': { id: 'greater-than-equals', name: ">=", fn: (a, {num}) => a >= num, values: () => [ golbinRaidValues['num'] ], }, 'in': { id: 'in', name: "In", fn: (a, {collection}) => collection.findIndex(({num}) => num == a) != -1, collection: true, values: () => [ golbinRaidValues['num'] ], }, 'not-in': { id: 'not-in', name: "Not In", fn: (a, {collection}) => collection.findIndex(({num}) => num == a) == -1, collection: true, values: () => [ golbinRaidValues['num'] ], }, 'includes': { id: 'includes', name: "Includes", fn: (a, {num}) => a.includes(num), values: () => [ golbinRaidValues['num'] ], }, 'not-includes': { id: 'not-includes', name: "Doesn't Include", fn: (a, {num}) => !a.includes(num), values: () => [ golbinRaidValues['num'] ], }, 'mod': { id: 'mod', name: "%", fn: (a, {num, mod}) => a % mod == num, values: () => [ golbinRaidValues['num'], golbinRaidValues['mod'] ], } } const golbinRaidConditionals = { wave: { id: 'wave', name: 'Wave', visible: true, selectable: true, params: [], evaluate: ({comparison, ...rest}) => { let a = raidManager.wave; return golbinRaidComparisons[comparison].fn(a, rest); }, comparisons: () => [ golbinRaidComparisons['equals'], golbinRaidComparisons['not-equals'], golbinRaidComparisons['less-than'], golbinRaidComparisons['less-than-equals'], golbinRaidComparisons['greater-than'], golbinRaidComparisons['greater-than-equals'], golbinRaidComparisons['mod'], golbinRaidComparisons['in'], golbinRaidComparisons['not-in'], ], values: () => [] }, equipment: { id: 'equipment', name: 'Equipment', visible: true, selectable: true, params: [ { id: 'slot', name: 'Slot', type: 'dropdown', default: -1, values: ({type}) => { let v = [...prioritiesList].map((id) => ({id: id, name: CONSTANTS.equipmentSlot[id]})) v.unshift({id: -1, name: 'Any'}); return v } }, { id: 'type', name: 'Type', type: 'dropdown', default: 'item', values: ({slot}) => { let v = []; v.push({id: 'item', name: 'Item'}) v.push({id: 'prio', name: 'Priority'}) if(slot != -1) v.push({id: 'stats', name: 'Stats'}) v.push({id: 'alt', name: 'Alt'}) if(slot != -1) v.push({id: 'special', name: 'Has Special'}) return v } }, { id: 'stat', name: 'Stat', type: 'dropdown', default: 'damageReduction', visible: ({type}) => type == 'stats', values: () => equipStatKeys.map(stat => { return {id: stat, name: camel2title(stat)}; }) } ], evaluate: ({comparison, slot, type, stat, ...rest}) => { let a = 0; if(type == 'special') a = raidManager.player.equipment.slotArray[slot].occupiedBy === 'None' && raidManager.player.altAttacks[CONSTANTS.equipmentSlot[slot]].length == 0 && raidManager.player.equipment.slotArray[slot].item.hasSpecialAttack; if(type == 'alt') a = raidManager.player.equipment.slotArray[slot].occupiedBy === 'None' && raidManager.player.altAttacks[CONSTANTS.equipmentSlot[slot]]; if(type == 'item') a = raidManager.player.equipment.slotArray[slot].item.id; if(type == 'stats') a = (raidManager.player.equipment.slotArray[slot].item.equipmentStats.find(i => i.key == stat) || {value: 0}).value; if(type == 'prio') { a = golbinRaiderPriorities[CONSTANTS.equipmentSlot[slot]] && golbinRaiderPriorities[CONSTANTS.equipmentSlot[slot]].length > 0 && golbinRaiderPriorities[CONSTANTS.equipmentSlot[slot]].findIndex(id => id == raidManager.player.equipment.slotArray[slot].item.id); if(a === false || a == -1) { a = Infinity; } else { a++; } } return golbinRaidComparisons[comparison].fn(a, rest); }, comparisons: ({slot, type}) => { let comparisons = [ golbinRaidComparisons['equals'], golbinRaidComparisons['not-equals'], ]; if(type == 'item') { comparisons = comparisons.concat([ golbinRaidComparisons['in'], golbinRaidComparisons['not-in'], ]) } if(type == 'stats' || type == 'prio') { comparisons = comparisons.concat([ golbinRaidComparisons['less-than'], golbinRaidComparisons['less-than-equals'], golbinRaidComparisons['greater-than'], golbinRaidComparisons['greater-than-equals'], ]) } if(type == 'alt' || slot == -1) { comparisons = [ golbinRaidComparisons['includes'], golbinRaidComparisons['not-includes'], ]; } if(type == 'special') { comparisons = [ golbinRaidComparisons['true'], golbinRaidComparisons['false'], ]; } return comparisons; }, values: ({type}) => { let values = []; if(type == 'item') values.push({ id: 'num', name: 'Item', type: 'dropdown', default: -1, values: ({slot}) => { let v = items.filter(item => slot == -1 ? item.validSlots && item.validSlots.length > 0 : item.validSlots && item.validSlots.includes(CONSTANTS.equipmentSlot[slot])); v.unshift({id: -1, name: 'Empty'}); return v; }, content: ({num}, collection) => `${num > -1 ? `<img class="skill-icon-xs mr-1" src="${CDNDIR}${items[num].media}"> ` : ''}${num > -1 ? items[num].name : 'Empty'}`, render: ({id, name}) => `${id > -1 ? `<img class="skill-icon-xs mr-1" src="${CDNDIR}${items[id].media}"> ` : ''} ${name}` }); if(type == 'alt') values.push({ id: 'num', name: 'Alts', type: 'dropdown', default: -1, values: ({slot}) => { let v = [...raidManager.specialAttackSelection].filter((attack, i, arr) => arr.findIndex(a => attack.id == a.id) == i); v.unshift({id: -1, name: 'Empty'}); return v; }, content: ({num}, collection) => `${collection.find(attack => attack.id == num).name}`, render: ({id, name, attackTypes}) => `${attackTypes && attackTypes.length == 1 ? `(${attackTypes[0].toUpperCase()})` : ''} ${name}` }); return values; } }, food: { id: 'food', name: 'Food', visible: true, selectable: true, params: [ { id: 'type', name: 'Type', default: 'qty', type: 'dropdown', values: () => ({healsFor: {id: 'healsFor', name: 'Heals For'}, qty: {id: 'qty', name: 'Quantity'}, total: {id: 'total', name: 'Total Healing'}}) } ], evaluate: ({comparison, type, ...rest}) => { let a = 0; if(type == 'healsFor') a = items[raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.id].healsFor; if(type == 'qty') a = raidManager.player.food.slots[raidManager.player.food.selectedSlot].quantity; if(type == 'total') a = items[raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.id].healsFor * raidManager.player.food.slots[raidManager.player.food.selectedSlot].quantity; return golbinRaidComparisons[comparison].fn(a, rest); }, comparisons: () => [ golbinRaidComparisons['less-than'], golbinRaidComparisons['less-than-equals'], golbinRaidComparisons['greater-than'], golbinRaidComparisons['greater-than-equals'], ], values: () => [] }, rune: { id: 'rune', name: 'Rune Count', visible: true, selectable: true, params: [ { id: 'type', name: 'Rune', type: 'dropdown', default: CONSTANTS.item.Air_Rune, values: () => Object.fromEntries(availableRunes().map(rune => [rune, items[rune]])), content: ({type}, collection) => `<img class="skill-icon-xs mr-1" src="${CDNDIR}${items[type].media}"> ${items[type].name}`, render: ({id, name}) => `<img class="skill-icon-xs mr-1" src="${CDNDIR}${items[id].media}"> ${name}` } ], evaluate: ({comparison, type, ...rest}) => { let a = golbinItemCount(type); return golbinRaidComparisons[comparison].fn(a, rest); }, comparisons: () => [ golbinRaidComparisons['less-than'], golbinRaidComparisons['less-than-equals'], golbinRaidComparisons['greater-than'], golbinRaidComparisons['greater-than-equals'], ], values: () => [] }, ammo: { id: 'ammo', name: 'Ammo Count', visible: true, selectable: true, params: [], evaluate: ({comparison, ...rest}) => { let a = raidManager.player.equipment.slotArray[CONSTANTS.equipmentSlot.Quiver].quantity; return golbinRaidComparisons[comparison].fn(a, rest); }, comparisons: () => [ golbinRaidComparisons['less-than'], golbinRaidComparisons['less-than-equals'], golbinRaidComparisons['greater-than'], golbinRaidComparisons['greater-than-equals'], ], values: () => [] }, stats: { id: 'stats', name: 'Stats', visible: true, selectable: true, params: [ { id: 'type', name: 'Type', default: 'damage-reduction', type: 'dropdown', values: () => { let stats = raidManager.player.stats.getValueTable(); stats.forEach(stat => stat.id = stat.name.toLowerCase().replace(' ', '-')); return stats.map(stat => stat); }, content: ({type}, collection) => `${collection.find(c => c.id == type).name}`, render: ({id, name}) => `${name}` } ], evaluate: ({comparison, type, ...rest}) => { let stats = raidManager.player.stats.getValueTable(); let stat = stats.find(stat => stat.name.toLowerCase().replace(' ', '-') == type); return golbinRaidComparisons[comparison].fn((stat || {value: 0}).value, rest); }, comparisons: () => [ golbinRaidComparisons['equals'], golbinRaidComparisons['not-equals'], golbinRaidComparisons['less-than'], golbinRaidComparisons['less-than-equals'], golbinRaidComparisons['greater-than'], golbinRaidComparisons['greater-than-equals'], ], values: () => [] }, or: { id: 'or', name: 'OR', visible: true, selectable: true, container: true, evaluate: ({conditions, ...rest}) => { return conditions.reduce((a,b) => a || golbinRaidConditionals[b.conditional].evaluate(b), false); } }, and: { id: 'and', name: 'AND', visible: true, selectable: true, container: true, evaluate: ({conditions, ...rest}) => { return conditions.reduce((a,b) => a && golbinRaidConditionals[b.conditional].evaluate(b), true); } }, default: { id: 'default', name: 'Default', visible: true, selectable: true, evaluate: ({...rest}) => { return true } }, result: { visible: false, selectable: false, evaluate: ({result, conditional, ...rest}) => { let ret = golbinRaidConditionals[conditional].evaluate(rest); if(result == 'passive' && raidManager.player.modifiers.golbinRaidPassiveSlotUnlocked == 0) ret = false; return result && ret ? result : ret; } } } function evaluateSteps(steps) { for(let i=0; i<steps.length; i++) { let result = golbinRaidConditionals.result.evaluate(steps[i]); if(result !== false) return { result: result, step: steps[i] }; } } window.evaluateSteps = evaluateSteps; function itemWeight(id, isAlt=false, slot=false) { let item = items[id]; if(!item) return -1; let equipmentStats = new EquipmentStats(item.equipmentStats); let weight = 0; weight += equipmentStats.attackSpeed / 1000 if(Math.max(equipmentStats.stabAttackBonus, equipmentStats.slashAttackBonus, equipmentStats.blockAttackBonus) > 0) weight += Math.max(equipmentStats.stabAttackBonus, equipmentStats.slashAttackBonus, equipmentStats.blockAttackBonus); if(equipmentStats.rangedAttackBonus > 0) weight += equipmentStats.rangedAttackBonus / 2; if(equipmentStats.magicAttackBonus > 0) weight += equipmentStats.magicAttackBonus / 2; if(equipmentStats.meleeStrengthBonus > 0) weight += equipmentStats.meleeStrengthBonus if(equipmentStats.rangedStrengthBonus > 0) weight += equipmentStats.rangedStrengthBonus / 2 if(equipmentStats.magicDamageBonus > 0) weight += equipmentStats.magicDamageBonus / 2 if(equipmentStats.meleeDefenceBonus > 0) weight += equipmentStats.meleeDefenceBonus if(equipmentStats.rangedDefenceBonus > 0) weight += equipmentStats.rangedDefenceBonus / 2 if(equipmentStats.magicDefenceBonus > 0) weight += equipmentStats.magicDefenceBonus / 2 weight += equipmentStats.damageReduction * 1000 if(combatLevel(item) >= 70) weight += 2500; if(combatLevel(item) >= 85) weight += 5000; if(item.validSlots.includes('Weapon') && item.occupiesSlots.includes('Shield')) weight = -1; if(item.attackType === "ranged" && item.validSlots.filter(slot => slot != CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive]).includes("Weapon")) weight = -1; if(item.attackType == "magic" && item.validSlots.filter(slot => slot != CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive]).includes("Weapon")) weight = -1; equipmentStats = null; return weight; } function generateTooltip(id, qty=1, isPassive=false, isAlt=false, slot=false, altAttacks=[]) { let item = items[id]; if(!item) return `<div class="text-center"><span class="text-warning">${slot}</span></div>`; if(!slot && item.validSlots !== undefined && item.validSlots.length > 0) slot = item.validSlots[0]; if(isPassive) slot = CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive]; let itemStat = ""; if (item.healsFor) itemStat += `<br><span class="text-white">Healing: ${(item.healsFor * qty).toFixed(2)}</span>`; if (isEquipment(item) && !isPassive && !(slot && golbinRaiderPriorities[slot] && golbinRaiderPriorities[slot].includes(id))) itemStat += `<br><span class="text-white">Weight: ${itemWeight(id, isAlt, slot)}</span>`; if(slot && golbinRaiderPriorities[slot] && golbinRaiderPriorities[slot].includes(id)) itemStat += `<br><span class="text-white">Priority: ${golbinRaiderPriorities[slot].indexOf(id) + 1}</span>`; if (isEquipment(item) && !isPassive && isAlt) itemStat += `<br><span class="text-warning">ALT</span>`; if (isEquipment(item) && !isPassive && isAlt && altAttacks.length > 0) itemStat += altAttacks.map((id)=>{ let attack = attacksIDMap.get(id); if(attack !== undefined) { return `<br><span class="text-danger">${attack.name} (${formatPercent(attack.defaultChance)}): <span class="text-warning">${describeAttack(attack)}</span></span>`; } else { return ``; } }).join(""); if (isEquipment(item) && !isPassive && !isAlt && item.hasSpecialAttack) itemStat += item.specialAttacks.map((attack)=>{ return `<br><span class="text-danger">${attack.name} (${formatPercent(attack.defaultChance)}): <span class="text-warning">${describeAttack(attack)}</span></span>`; }).join(""); if (item.description != undefined) itemStat += `<br><span class="text-info">${item.description}</span>`; if (!isPassive) { let equipStats = item.equipmentStats; if(equipStats) { equipStats.forEach((stat)=>{ itemStat += '<br>'; if (stat.value > 0) { itemStat += Equipment.getEquipStatDescription(stat.key, stat.value); } else { itemStat += `<span class="text-danger">${Equipment.getEquipStatDescription(stat.key, stat.value)}</span>`; } }); } } return `<div class="text-center"><span class="text-warning">${item.name}</span><small class='text-success'>${itemStat}</small></div>`; } function generateSpecialTooltip(specialAttacks=[]) { let allAttacks = specialAttacks.map((slot, i) => { if(slot.length == 0) return ""; let specials = slot.map((id)=>{ let attack = attacksIDMap.get(id); if(attack !== undefined) { return `<br><span class="text-danger">${attack.name} (${formatPercent(attack.defaultChance)}): <span class="text-warning">${describeAttack(attack)}</span></span>`; } else { return ""; } }).join(""); return `<br><span class="text-success">${CONSTANTS.equipmentSlot[i]}</span><small class='text-warning'>${specials}</small>` }).join(""); return `<div class="text-center"><span class="text-warning">Special Attacks</span>${allAttacks}</div>`; } function generateItemImage(id, qty=0, selected=false, current=false, slot=false, isAlt=false, altAttacks=[]) { return ` <item-icon class="draggable" data-id="${id}" data-qty="${qty}" data-slot="${slot}" data-is-alt="${isAlt}" data-alt-attacks="${JSON.stringify(altAttacks)}" data-is-passive="${slot === CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive]}" style="display: inline-block; position: relative; height: 59px; width: 59px;" draggable="true"> <img class="combat-equip-img border border-2x border-rounded-equip border-combat-outline p-1 ${selected ? 'border-info' : ''} ${isAlt && !selected ? 'border-warning' : ''}" src="${CDNDIR + (id != -1 && items[id] ? items[id].media : (slot!==false ? 'assets/media/bank/' + equipmentSlotData[slot].emptyMedia + '.png' : 'assets/media/bank/passive_slot.png'))}" style="${current ? 'border-color: #e56767 !important;' : ''}" /> <div class="font-size-sm text-white text-center ${qty <= 1 ? 'd-none' : ''}" style="position: absolute; bottom: 0px; width: 100%;"> <small class="badge-pill bg-secondary">${qty}</small> </div> </item-icon> `; } function generateRuneImage(runeCount=false) { return ` <rune-icon style="display: inline-block; position: relative; height: 59px; width: 59px;" data-rune-count='${JSON.stringify(runeCount)}'> <img class="combat-equip-img border border-2x border-rounded-equip border-combat-outline p-1" src="${CDNDIR + items[CONSTANTS.item.Rune_Essence].media}"/> </rune-icon> ` } function generateSpecialImage(currentItems=false) { let specialAttacks = currentItems.map((slot, i) => { if(slot.isAlt) return slot.altAttacks; if(slot.id == -1 || i == CONSTANTS.equipmentSlot.Passive) return []; let item = items[slot.id]; if(isEquipment(item) && item.hasSpecialAttack) return item.specialAttacks.map(attack => attack.id); return []; }); if(specialAttacks.flat().length > 0) return ` <special-icon style="display: inline-block; position: relative; height: 59px; width: 59px;" data-special-attacks='${JSON.stringify(specialAttacks)}'> <img class="combat-equip-img border border-2x border-rounded-equip border-combat-outline p-1" src="${CDNDIR}assets/media/main/special_attack.svg"/> </rune-icon> `; return ""; } function generateEquipmentGrid(currentItems=false, currentRunes=false, currentFood=false) { let equipMap = [CONSTANTS.equipmentSlot.Passive, CONSTANTS.equipmentSlot.Helmet, -1, CONSTANTS.equipmentSlot.Cape, CONSTANTS.equipmentSlot.Amulet, CONSTANTS.equipmentSlot.Quiver, CONSTANTS.equipmentSlot.Weapon, CONSTANTS.equipmentSlot.Platebody, CONSTANTS.equipmentSlot.Shield, -1, CONSTANTS.equipmentSlot.Platelegs, -1, CONSTANTS.equipmentSlot.Gloves, CONSTANTS.equipmentSlot.Boots, CONSTANTS.equipmentSlot.Ring, (currentRunes ? -2 : -1), -1, (currentFood ? -3 : -1)]; return `<div class="text-center"><span class="text-warning">Equipment</span> <equipment-grid style="display: grid; grid-template-rows: 60px 60px 60px 60px 60px 60px; grid-template-columns: 60px 60px 60px;"> ${equipMap.map(slot => { if(slot > -1) { return generateItemImage(currentItems[slot].id, currentItems[slot].qty, false, false, CONSTANTS.equipmentSlot[slot], currentItems[slot].isAlt, currentItems[slot].altAttacks); } else if (slot == -2) { return generateRuneImage(currentRunes) } else if (slot == -3) { return generateItemImage(currentFood.id, currentFood.qty, false, false, CONSTANTS.equipmentSlot[slot]); } else { return `<div></div>` } }).join('')} </equipment-grid> </div>`; } function generateRuneGrid(runeCount=false) { return `<div class="text-center"><span class="text-warning">Runes</span> <rune-grid style="display: grid; grid-template-rows: 60px 60px 60px; grid-template-columns: 60px 60px 60px 60px;"> ${runeCount.map(rune => generateItemImage(rune[0], rune[1], true, false)).join('')} </rune-grid> </div>`; } function itemOnShow(instance) { let id = parseInt(instance.reference.dataset.id); let qty = parseInt(instance.reference.dataset.qty); let isAlt = instance.reference.dataset.isAlt === "true"; let altAttacks = JSON.parse(instance.reference.dataset.altAttacks); let isPassive = instance.reference.dataset.isPassive === "true"; let slot = instance.reference.dataset.slot; if(slot === "false") slot = false; instance.setContent(generateTooltip(id, qty, isPassive, isAlt, slot, altAttacks)); } function itemOnHidden(instance) { instance.setContent(''); } function specialOnShow(instance) { let specialAttacks = JSON.parse(instance.reference.dataset.specialAttacks); instance.setContent(generateSpecialTooltip(specialAttacks)); } function specialOnHidden(instance) { instance.setContent(''); } function runeOnShow(instance) { let runeCount = JSON.parse(instance.reference.dataset.runeCount); instance.setContent(generateRuneGrid(runeCount)); tippy($('item-icon', instance.popper.children[0].children[0]).toArray(), { content: '', allowHTML: true, placement: "left", interactive: false, animation: false, onShow: itemOnShow, onHidden: itemOnHidden }); } function runeOnHidden(instance) { $('item-icon', instance.popper.children[0].children[0]).toArray().forEach(el => { if(el._tippy) { el._tippy.destroy(); } }); instance.setContent(''); } function equipmentOnShow(instance) { let currentItems = JSON.parse(instance.reference.dataset.currentItems); let currentRunes = JSON.parse(instance.reference.dataset.currentRunes); let currentFood = JSON.parse(instance.reference.dataset.currentFood); instance.setContent(generateEquipmentGrid(currentItems, currentRunes, currentFood)); tippy($('item-icon', instance.popper.children[0].children[0]).toArray(), { content: '', allowHTML: true, placement: "left", interactive: false, animation: false, onShow: itemOnShow, onHidden: itemOnHidden }); tippy($('rune-icon', instance.popper.children[0].children[0]).toArray(), { content: '', allowHTML: true, placement: "left", interactive: true, animation: false, onShow: runeOnShow, onHidden: runeOnHidden }); } function equipmentOnHidden(instance) { $('item-icon', instance.popper.children[0].children[0]).toArray().forEach(el => { if(el._tippy) { el._tippy.destroy(); } }); instance.setContent(''); } function addChoice(category, selected, options, currentItems, currentRunes, currentFood, extra={}) { if(extra.oldPassive) { if(extra.oldPassive == -1) { currentItems[CONSTANTS.equipmentSlot.Passive].id = -1; } else { currentItems[CONSTANTS.equipmentSlot.Passive].id = extra.oldPassive; } } let logEntry = ` <entry style="display: grid; grid-template-rows: 60px; grid-template-columns: auto 1fr auto auto auto; margin-top: 5px; height: 60px; width: 100%; ${raidManager.wave == 1 ? 'border-bottom: 2px solid black;' : ''}" data-wave="${raidManager.wave}" data-category="${category}" data-selected="${selected}" data-options='${JSON.stringify(options)}'> <wave style="display: inline-block; grid-area: 1 / 1 / 1 / 1; font-size: 36px; line-height: 60px; height: 60px; color: white; margin-top: -2px; margin-left: 10px; min-width: 65px;" data-wave='${raidManager.wave}' data-current-items='${JSON.stringify(currentItems)}' data-current-runes='${JSON.stringify(currentRunes)}' data-current-food='${JSON.stringify(currentFood)}'> ${raidManager.wave} </wave> <special style="display: flex; grid-area: 1 / 2 / 1 / 2"> ${generateSpecialImage(currentItems)} </special> <existing-items style="display: flex; justify-content: flex-end; grid-area: 1 / 3 / 1 / 3;"> ${selected == -1 && category == 'weapons' ? generateItemImage(currentItems[CONSTANTS.equipmentSlot.Weapon].id, 0, true, false, CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Weapon], currentItems[CONSTANTS.equipmentSlot.Weapon].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks) : ''} ${selected == -1 && category == 'armour' ? options.filter((value, index, self) => self.map(item => items[item.itemID].validSlots[0]).indexOf(items[value.itemID].validSlots[0]) === index).map((item, i, self) => generateItemImage(currentItems[CONSTANTS.equipmentSlot[items[item.itemID].validSlots[0]]].id, 0, true, false, false, currentItems[CONSTANTS.equipmentSlot[items[item.itemID].validSlots[0]]].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks)).join('') : ''} ${selected == -1 && category == 'food' ? generateItemImage(currentFood.id, currentFood.qty, true, false) : ''} ${selected == -1 && category == 'ammo' ? generateItemImage(currentItems[CONSTANTS.equipmentSlot.Quiver].id, currentItems[CONSTANTS.equipmentSlot.Quiver].qty, true, false, false, currentItems[CONSTANTS.equipmentSlot.Quiver].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks) : ''} ${selected == -1 && category == 'runes' ? generateRuneImage(currentRunes) : ''} ${selected == -1 && category == 'passive' ? generateItemImage(currentItems[CONSTANTS.equipmentSlot.Passive].id, 0, true, false, CONSTANTS.equipmentSlot.Passive, currentItems[CONSTANTS.equipmentSlot.Passive].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks) : ''} ${selected > -1 && category == 'weapons' ? generateItemImage(currentItems[CONSTANTS.equipmentSlot.Weapon].id, 0, false, true, CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Weapon], currentItems[CONSTANTS.equipmentSlot.Weapon].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks) : ''} ${selected > -1 && category == 'armour' ? options.map((item, i, self) => (self.map(option => items[option.itemID].validSlots[0]).findIndex((slot, idx) => items[item.itemID].validSlots[0] == items[options[selected].itemID].validSlots[0] ? selected == idx : items[item.itemID].validSlots[0] == slot) == i) ? generateItemImage(currentItems[CONSTANTS.equipmentSlot[items[item.itemID].validSlots[0]]].id, 0, false, selected == i, items[item.itemID].validSlots[0], currentItems[CONSTANTS.equipmentSlot[items[item.itemID].validSlots[0]]].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks) : '').join('') : ''} ${selected > -1 && category == 'food' ? generateItemImage(currentFood.id, currentFood.qty, options[selected].itemID == currentFood.id, options[selected].itemID != currentFood.id) : ''} ${selected > -1 && category == 'ammo' ? generateItemImage(currentItems[CONSTANTS.equipmentSlot.Quiver].id, currentItems[CONSTANTS.equipmentSlot.Quiver].qty, options[selected].itemID == currentItems[CONSTANTS.equipmentSlot.Quiver].id, options[selected].itemID != currentItems[CONSTANTS.equipmentSlot.Quiver].id, false, currentItems[CONSTANTS.equipmentSlot.Quiver].isAlt, currentItems[CONSTANTS.equipmentSlot.Weapon].altAttacks) : ''} ${selected > -1 && category == 'runes' ? generateRuneImage(currentRunes) : ''} ${selected > -1 && category == 'passive' ? generateItemImage(currentItems[CONSTANTS.equipmentSlot.Passive].id, 0, false, true, CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive], false) : ''} </existing-items> <span style="grid-area: 1 / 4 / 1 / 4; font-size: 36px; line-height: 60px; height: 60px; color: white; margin-top: -2px; margin-left: 5px; margin-right: 5px;">-></span> <item-options style="display: inline-block; grid-area: 1 / 5 / 1 / 5; margin-right: 10px;"> ${options.map((item, i) => (item != undefined && item.itemID != undefined && item.itemID > -1) ? generateItemImage(item.itemID, item.qty, selected == i, false, items[item.itemID].validSlots != undefined ? (category == 'passive' ? CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive] : items[item.itemID].validSlots[0]) : false, item.isAlt, item.altAttacks) : '').join('')} </item-options> </entry>`; $('log').prepend(logEntry); tippy($('item-icon', $('log').get(0).children[0]).toArray(), { content: '', allowHTML: true, placement: "left", interactive: false, animation: false, onShow: itemOnShow, onHidden: itemOnHidden, }); tippy($('special-icon', $('log').get(0).children[0]).toArray(), { content: '', allowHTML: true, placement: "left", interactive: false, animation: false, onShow: specialOnShow, onHidden: specialOnHidden, }); tippy($('rune-icon', $('log').get(0).children[0]).toArray(), { content: '', allowHTML: true, placement: "left", interactive: true, animation: false, onShow: runeOnShow, onHidden: runeOnHidden, }); tippy($('wave', $('log').get(0).children[0]).get(0), { content: '', allowHTML: true, placement: "left", interactive: true, animation: false, onShow: equipmentOnShow, onHidden: equipmentOnHidden, appendTo: () => document.body }); if($('log').get(0).children.length > 25) { let entries = $('log').get(0).children; $('item-icon', entries[entries.length-1]).toArray().forEach(el => { if(el._tippy) el._tippy.destroy(); }); $('rune-icon', entries[entries.length-1]).toArray().forEach(el => { if(el._tippy) el._tippy.destroy(); }); $('wave', entries[entries.length-1]).toArray().forEach(el => { if(el._tippy) el._tippy.destroy(); }); if(entries[entries.length-1]._tippy) entries[entries.length-1]._tippy.destroy(); $('log').get(0).removeChild(entries[entries.length-1]); entries = null; } } function generateModifiersTab() { //modifierData //RaidManager.possibleModifiers /* const playerMods = new MappedModifiers(); playerMods.addArrayModifiers(this.randomPlayerModifiers); const golbinMods = new MappedModifiers(); golbinMods.addArrayModifiers(this.randomEnemyModifiers); ...playerMods.getActiveModifierDescriptions() ...golbinMods.getActiveModifierDescriptions() */ return ` <div style='display: grid; grid-template-rows: 60px 1fr; justify-items: start; align-items: center; position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow-y: scroll;'> <buttons style='display: grid; grid-template-rows: 60px; grid-template-columns: repeat(2, 1fr); justify-items: center; align-items: center; width: 100%;'> <button class='btn m-1 btn-outline-success' onclick="showGolbinRaiderModifiers('positive')">Positive</button> <button class='btn m-1 btn-outline-danger' onclick="showGolbinRaiderModifiers('negative')">Negative</button> </buttons> <modifiers style='display: grid; grid-template-columns: 1fr; grid-auto-flow: row; margin: 10px;'></modifiers> </div> `; } let sortableModifiersInstance = false; function updateGolbinModifierSoftCap(type, key, val) { golbinRaiderModifierPriority[type].find(m => m.key == key).soft = parseInt(val); localStorage.setItem(`golbinRaiderModifierPriority`, JSON.stringify(golbinRaiderModifierPriority)); } window.updateGolbinModifierSoftCap = updateGolbinModifierSoftCap; function updateGolbinModifierHardCap(type, key, val) { golbinRaiderModifierPriority[type].find(m => m.key == key).hard = parseInt(val); localStorage.setItem(`golbinRaiderModifierPriority`, JSON.stringify(golbinRaiderModifierPriority)); } window.updateGolbinModifierHardCap = updateGolbinModifierHardCap; function showGolbinRaiderModifiers(type) { if(sortableModifiersInstance) { sortableModifiersInstance.destroy(); sortableModifiersInstance = false; } let buttons = $('buttons button', $('sidebar container tabs tab.modifiers')).toArray() buttons[0].classList.remove('btn-secondary'); buttons[1].classList.remove('btn-secondary'); if(type == 'positive') buttons[0].classList.add('btn-secondary'); if(type == 'negative') buttons[1].classList.add('btn-secondary'); let posHead = getLangString('GOLBIN_RAID', type == 'positive' ? 'GIVES_YOU' : 'GIVES_GOLBINS'); let negHead = getLangString('GOLBIN_RAID', type == 'positive' ? 'GIVES_GOLBINS' : 'GIVES_YOU'); let textClass = type == 'positive' ? 'text-success' : 'text-danger'; $('sidebar container tabs tab.modifiers modifiers').get(0).innerHTML = ''; $('sidebar container tabs tab.modifiers modifiers').append(` <header style='display: grid; grid-template-columns: 1fr repeat(2, 100px); grid-auto-flow: row; align-items: center;'> <span class='text-white'>Modifier</span> <span class='text-white'>Soft Cap</span> <span class='text-white'>Hard Cap</span> </header>`); let sortedModifiers = [...RaidManager.possibleModifiers].sort((a,b) => golbinRaiderModifierPriority[type].findIndex(m => m.key == a.key) - golbinRaiderModifierPriority[type].findIndex(m => m.key == b.key)); $('sidebar container tabs tab.modifiers modifiers').append(sortedModifiers.map(mod => { const modData = modifierData[mod.key]; let min = 1; let max = 5; if(mod.multiplier !== undefined) { min *= mod.multiplier; max *= mod.multiplier; } if(modData.modifyValue !== undefined) { min = modData.modifyValue(min); max = modData.modifyValue(max); } let val = `<span class='text-warning'>(${min}-${max})</span>`; const text = `${modData.isNegative ? negHead : posHead} ${templateString(modifierData[mod.key].langDescription, {value: val})}`; return `<modifier style='display: grid; grid-template-columns: 1fr repeat(2, 100px); grid-auto-flow: row; align-items: center;'> <span class='${textClass}'> <small>${text}</small> </span> <value style="display: inline-block; width: 100px;"> <input type="number" min="0" class="form-control m-1" placeholder="" value="${golbinRaiderModifierPriority[type].find(m => m.key == mod.key).soft}" oninput='updateGolbinModifierSoftCap("${type}", "${mod.key}", this.value)'> </value> <value style="display: inline-block; width: 100px;"> <input type="number" min="0" class="form-control m-1" placeholder="" value="${golbinRaiderModifierPriority[type].find(m => m.key == mod.key).hard}" oninput='updateGolbinModifierHardCap("${type}", "${mod.key}", this.value)'> </value> </modifier>`; }).join('')); sortableModifiersInstance = Sortable.create($('sidebar container tabs tab.modifiers modifiers').get(0), { group: `golbinRaiderModifiers`, draggable: "modifier", filter: "header", handle: ".text-success, .text-danger", onEnd: (evt) => { golbinRaiderModifierPriority[type].splice(evt.newDraggableIndex, 0, golbinRaiderModifierPriority[type].splice(evt.oldDraggableIndex, 1)[0]); localStorage.setItem(`golbinRaiderModifierPriority`, JSON.stringify(golbinRaiderModifierPriority)); }, onMove: function() { tippy.hideAll(); }, onChoose: function(evt) { tippy.hideAll(); }, }); } window.showGolbinRaiderModifiers = showGolbinRaiderModifiers; function generatePrioritiesTab() { return ` <priorities style='display: grid; grid-template-rows: repeat(2, 60px); grid-template-columns: repeat(6, 60px); justify-items: center; align-items: center;'> ${prioritiesList.map(slot => `<priority onclick="showGolbinRaiderPriority('${CONSTANTS.equipmentSlot[slot]}')">${generateItemImage(-1, 0, false, false, CONSTANTS.equipmentSlot[slot])}</priority>`).join('')} </priorities> <itemlist style='height: 100%; width: 100%;'></itemlist> `; }; function showGolbinRaiderItemSelect(slot, index) { $("#modal-golbinraider-item-select").get(0).dataset.slot = slot; $("#modal-golbinraider-item-select").get(0).dataset.index = index; updateGolbinRaiderItemSearch(''); $("#modal-golbinraider-item-select").modal("show"); } let sortableInstance = false; function showGolbinRaiderPriority(slot) { if(sortableInstance) { sortableInstance.destroy(); sortableInstance = false; } $('item-icon img', $('sidebar container tabs tab priorities').get(0)).toArray().forEach((el, i) => { el.classList.remove('border-info'); if(CONSTANTS.equipmentSlot[prioritiesList[i]] == slot) el.classList.add('border-info'); }); $('sidebar container tabs tab itemlist').get(0).innerHTML = ''; $('sidebar container tabs tab itemlist').append(golbinRaiderPriorities[slot].map(id => generateItemImage(id, 0, false, false, slot)).join('')); $('sidebar container tabs tab itemlist').append(generateItemImage(-1, 0, false, false, slot)); sortableInstance = Sortable.create($('sidebar container tabs tab itemlist').get(0), { group: `golbinRaiderPriority-${slot}`, draggable: "item-icon", onEnd: (evt) => { golbinRaiderPriorities[slot].splice(evt.newIndex, 0, golbinRaiderPriorities[slot].splice(evt.oldIndex, 1)[0]); golbinRaiderPriorities[slot] = golbinRaiderPriorities[slot].filter(id => id > -1); localStorage.setItem(`golbinRaiderPriorities`, JSON.stringify(golbinRaiderPriorities)); }, onMove: function() { tippy.hideAll(); }, onChoose: function(evt) { tippy.hideAll(); }, }); $('item-icon', $('sidebar container tabs tab itemlist').get(0)).toArray().forEach((el, i) => { el.setAttribute('onclick', `showGolbinRaiderItemSelect('${slot}', ${i})`); }); tippy($('item-icon', $('sidebar container tabs tab itemlist').get(0)).toArray(), { content: '', allowHTML: true, placement: "left", interactive: false, animation: false, onShow: itemOnShow, onHidden: itemOnHidden }); } function generateDropdown(collection=[], selected=-1, content=() => `<img class="skill-icon-xs mr-1" src="${CDNDIR}assets/media/main/bank_header.svg">`, render=({media, name}) => `<a class="dropdown-item pointer-enabled"><img class="skill-icon-xs mr-1" src="${media}">${name}</a>`) { return ` <div class="dropdown" style="margin: 0 5px; display: inline-block;"> <button type="button" class="btn btn-dark dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> ${content(selected, collection.map ? collection : Object.values(collection))} </button> <div class="dropdown-menu dropdown-menu-right font-size-sm overflow-y-auto" style="max-height:80vh;"> ${(collection.map ? collection : Object.values(collection)).map(item => render(item)).join('')} </div> </div> `; } function triggerStepsSave() { localStorage.setItem(`golbinRaiderSelectionSteps`, JSON.stringify(golbinRaiderSelectionSteps)); } function getConditionAndStep(idxs) { let path = idxs.length ? [...idxs] : [idxs]; let i = path.shift(); let condition = golbinRaiderSelectionSteps[i]; let step = $('steps > sortable-steps > step, steps > step').get(i); if(path.length > 0) { condition = path.reduce((a,b) => a.conditions[b], condition); step = path.reduce((a,b) => $('> conditional > conditions > step', a).get(b), step); } return {condition: condition, step: step}; } function updateGolbinRaiderConditional(idxs, id) { let { condition, step } = getConditionAndStep(idxs); let el = $('> conditional', step).get(0); let old = condition.conditional; condition.conditional = id; if(golbinRaidConditionals[old].params) golbinRaidConditionals[old].params.forEach(param => delete condition[param.id]); if(golbinRaidConditionals[id].params) golbinRaidConditionals[id].params.forEach(param => param.visible === undefined || param.visible(condition) ? condition[param.id] = param.default : ''); if(golbinRaidConditionals[old].container && !golbinRaidConditionals[id].container) delete condition.conditions; if(!golbinRaidConditionals[old].container && golbinRaidConditionals[id].container) { delete condition.comparison; condition.conditions = []; } if(condition.comparison) { if(golbinRaidComparisons[condition.comparison].collection) { delete condition.collection; } else { let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[old].values) { golbinRaidConditionals[old].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } if(values.length > 0) values.forEach(value => delete condition[value.id]); } } let comparisons = golbinRaidConditionals[id].comparisons && golbinRaidConditionals[id].comparisons(condition); if(comparisons && comparisons.length > 0) { if(comparisons.findIndex(comp => comp.id == condition.comparison) == -1) condition.comparison = comparisons[0].id; } else { delete condition.comparison; } if(condition.comparison) { if(golbinRaidComparisons[condition.comparison].collection) { condition.collection = []; } else { let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[id].values) { golbinRaidConditionals[id].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } if(values.length > 0) values.forEach(value => condition[value.id] = value.default); } } el.outerHTML = generateConditional(idxs, condition); triggerStepsSave(); } window.updateGolbinRaiderConditional = updateGolbinRaiderConditional; function updateGolbinRaiderComparison(idxs, id) { let { condition, step } = getConditionAndStep(idxs); let el = $('> conditional > comparison', step).get(0); let old = condition.comparison; condition.comparison = id; let oldValues = [...golbinRaidComparisons[old].values(condition)]; let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let oldIdx = oldValues.findIndex(v => v.id == val.id); let idx = values.findIndex(v => v.id == val.id); if(oldIdx > -1) oldValues[oldIdx] = val; if(idx > -1) values[idx] = val; }); } if(golbinRaidComparisons[old].collection && golbinRaidComparisons[id].collection) { if(oldValues.length > 0) { oldValues.forEach(value => { let vIdx = values.findIndex(val => val.id == value.id); if(vIdx == -1 || values[vIdx].type != value.type) { condition.collection.forEach(item => { delete item[value.id]; }); } }); } if(values.length > 0) { values.forEach((value, i) => { let vIdx = oldValues.findIndex(val => val.id == value.id); if(vIdx == -1 || oldValues[vIdx].type != value.type) { condition.collection.forEach((item, j) => { item[value.id] = value.default; updateGolbinRaiderValue(idxs, value.id, condition[value.id]); }); } }); } } else if(golbinRaidComparisons[old].collection && !golbinRaidComparisons[id].collection) { delete condition.collection; if(values.length > 0) { values.forEach((value, i) => { condition[value.id] = value.default; updateGolbinRaiderValue(idxs, value.id, condition[value.id]); }); } } else if(!golbinRaidComparisons[old].collection && golbinRaidComparisons[id].collection) { condition.collection = []; if(oldValues.length > 0) oldValues.forEach(value => delete condition[value.id]); } else { if(values.length > 0) { values.forEach((value, i) => { let vIdx = oldValues.findIndex(val => val.id == value.id); if(vIdx == -1 || oldValues[vIdx].type != value.type) { condition[value.id] = value.default; } updateGolbinRaiderValue(idxs, value.id, condition[value.id]); }); } } el.outerHTML = generateComparison(idxs, condition); triggerStepsSave(); } window.updateGolbinRaiderComparison = updateGolbinRaiderComparison; function updateGolbinRaiderResult(idxs, id) { let { condition, step } = getConditionAndStep(idxs); let el = $('> conditional > result', step).get(0); condition.result = id; el.outerHTML = generateResult(idxs, condition); triggerStepsSave(); } window.updateGolbinRaiderResult = updateGolbinRaiderResult; function updateGolbinRaiderParameter(idxs, i, id) { let { condition, step } = getConditionAndStep(idxs); let els = $('> conditional > parameters', step); let param = golbinRaidConditionals[condition.conditional].params[i]; let oldCondition = { ...condition } condition[param.id] = id; for(let j=0; j < golbinRaidConditionals[condition.conditional].params.length; j++) { let p = golbinRaidConditionals[condition.conditional].params[j]; if(p.visible === undefined || p.visible(condition)) { let values = p.values && p.values(condition); if(values && values.length > 0) { if(values.findIndex(val => val.id == condition[p.id]) == -1) { condition[p.id] = values[0].id; } } } else { delete condition[p.id]; } } for(let j=0; j < golbinRaidConditionals[condition.conditional].params.length; j++) { let p = golbinRaidConditionals[condition.conditional].params[j]; let el = $('parameter', els).get(j); if(p.visible === undefined || p.visible(condition)) { if(el === undefined) { condition[p.id] = p.default; els.append(generateParam(idxs, j, condition)); } else { el.outerHTML = generateParam(idxs, j, condition); } } else { if(el !== undefined) { el.outerHTML = ''; } } } let comparisons = golbinRaidConditionals[condition.conditional].comparisons && golbinRaidConditionals[condition.conditional].comparisons(condition); if(comparisons && comparisons.length > 0) { if(comparisons.findIndex(comp => comp.id == condition.comparison) == -1) { condition.comparison = comparisons[0].id; } updateGolbinRaiderComparison(idxs, condition.comparison); } else { delete condition.comparison; } let oldValues = [...golbinRaidComparisons[oldCondition.comparison].values(oldCondition)]; let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } if(golbinRaidConditionals[oldCondition.conditional].values) { golbinRaidConditionals[oldCondition.conditional].values(oldCondition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) oldValues[idx] = val; }); } if(golbinRaidComparisons[oldCondition.comparison].collection && golbinRaidComparisons[condition.comparison].collection) { if(oldValues.length > 0) { oldValues.forEach(value => { let vIdx = values.findIndex(val => val.id == value.id); if(vIdx == -1 || values[vIdx].type != value.type) { condition.collection.forEach(item => { delete item[value.id]; }); } }); } if(values.length > 0) { values.forEach((value, i) => { let vIdx = oldValues.findIndex(val => val.id == value.id); if(vIdx == -1 || oldValues[vIdx].type != value.type) { condition.collection.forEach((item, j) => { item[value.id] = value.default; updateGolbinRaiderValue(idxs, value.id, condition[value.id]); }); } }); } } else if(golbinRaidComparisons[oldCondition.comparison].collection && !golbinRaidComparisons[condition.comparison].collection) { delete condition.collection; if(values.length > 0) { values.forEach((value, i) => { condition[value.id] = value.default; updateGolbinRaiderValue(idxs, value.id, condition[value.id]); }); } } else if(!golbinRaidComparisons[oldCondition.comparison].collection && golbinRaidComparisons[condition.comparison].collection) { condition.collection = []; if(oldValues.length > 0) oldValues.forEach(value => delete condition[value.id]); } else { if(values.length > 0) { values.forEach((value, i) => { let vIdx = oldValues.findIndex(val => val.id == value.id); if(vIdx == -1 || oldValues[vIdx].type != value.type) { condition[value.id] = value.default; } updateGolbinRaiderValue(idxs, value.id, condition[value.id]); }); } } triggerStepsSave(); } window.updateGolbinRaiderParameter = updateGolbinRaiderParameter; function updateGolbinRaiderValue(idxs, i, id, collectionIdx=-1) { let { condition, step } = getConditionAndStep(idxs); let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } let value = values.find(val => val.id == i); let valueIdx = values.findIndex(val => val.id == i); let els = $('> conditional > comparison > values', step).get(0); let el = $('> value, > value-collection > value', els).get(collectionIdx > -1 ? collectionIdx : valueIdx); if(collectionIdx > -1) { condition.collection[collectionIdx][i] = id; } else { condition[i] = id; } if(el && !el.contains(document.activeElement)) // Fixes redrawing text boxes while editing el.outerHTML = generateValue(idxs, i, condition, collectionIdx); triggerStepsSave(); } window.updateGolbinRaiderValue = updateGolbinRaiderValue; function addGolbinRaiderStep(idxs=-1) { if(idxs == -1) { golbinRaiderSelectionSteps.splice(golbinRaiderSelectionSteps.length-1, 0, {conditional: 'default', result: 'food'}); $('steps > sortable-steps').append(generateStep([golbinRaiderSelectionSteps.length-2], golbinRaiderSelectionSteps[golbinRaiderSelectionSteps.length-2])); $('steps > step').get(0).outerHTML = generateStep([golbinRaiderSelectionSteps.length-1], golbinRaiderSelectionSteps[golbinRaiderSelectionSteps.length-1]); } else { let { condition, step } = getConditionAndStep(idxs); condition.conditions.push({conditional: 'default'}); $('> conditional > conditions > add-condition', step).before(generateStep(idxs.concat([condition.conditions.length-1]), condition.conditions[condition.conditions.length-1])); } triggerStepsSave(); } window.addGolbinRaiderStep = addGolbinRaiderStep; function addGolbinRaiderValueCollection(idxs) { let { condition, step } = getConditionAndStep(idxs); let valuesRoot = $('> conditional > comparison > values', step).get(0); let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } let newValues = {}; if(values.length > 0) values.forEach(value => newValues[value.id] = value.default); condition.collection.push(newValues); $('add-value', valuesRoot).before(generateValueCollection(idxs, condition, condition.collection.length-1)); triggerStepsSave(); } window.addGolbinRaiderValueCollection = addGolbinRaiderValueCollection; function removeGolbinRaiderValueCollection(idxs, collectionIdx) { let { condition, step } = getConditionAndStep(idxs); $('> conditional > comparison > values > value-collection', step).get(collectionIdx).outerHTML = ''; condition.collection.splice(collectionIdx, 1); for(let i=collectionIdx; i<condition.collection.length; i++) $('> conditional > comparison > values > value-collection', step).get(i).outerHTML = generateValueCollection(idxs, condition, i); triggerStepsSave(); } window.removeGolbinRaiderValueCollection = removeGolbinRaiderValueCollection; function removeGolbinRaiderStep(idxs) { if(idxs.length == 1) { let { condition, step } = getConditionAndStep(idxs); golbinRaiderSelectionSteps.splice(idxs[0], 1); step.outerHTML = ''; for(let i=idxs[0]; i<golbinRaiderSelectionSteps.length-1; i++) $('steps > sortable-steps > step').get(i).outerHTML = generateStep([i], golbinRaiderSelectionSteps[i]); $('steps > step').get(0).outerHTML = generateStep([golbinRaiderSelectionSteps.length-1], golbinRaiderSelectionSteps[golbinRaiderSelectionSteps.length-1]); } else { let { step } = getConditionAndStep(idxs); let idx = idxs.pop(); let { condition, step: conditionRoot } = getConditionAndStep(idxs); step.outerHTML = ''; condition.conditions.splice(idx, 1); for(let i=idx; i<condition.conditions.length; i++) $('> conditional > conditions > step', conditionRoot).get(i).outerHTML = generateStep(idxs.concat(i), condition.conditions[i]); } triggerStepsSave(); } window.removeGolbinRaiderStep = removeGolbinRaiderStep; function generateConditional(idxs, condition) { let conditional = `<conditional style="display: flex; align-items: center;">`; if(golbinRaidConditionals[condition.conditional].selectable && !golbinRaidConditionals[condition.conditional].visible) { conditional += `<div class="btn btn-dark">${golbinRaidConditionals[condition.conditional].name}</div>` } else { conditional += ` ${generateDropdown(golbinRaidConditionals, condition, ({conditional}) => golbinRaidConditionals[conditional].name, ({id, name, selectable, visible}) => (selectable && visible ? `<a class='dropdown-item pointer-enabled' onclick='updateGolbinRaiderConditional(${JSON.stringify(idxs)}, ${typeof id == 'number' || typeof id == 'boolean' ? id : `"${id}"`})'>${name}</a>` : ''))} `; } if(golbinRaidConditionals[condition.conditional].params && golbinRaidConditionals[condition.conditional].params.length > 0) { conditional += ` <parameters> ${golbinRaidConditionals[condition.conditional].params.map((param, i) => generateParam(idxs, i, condition)).join('')} </parameters>`; } if(condition.comparison) { conditional += generateComparison(idxs, condition); } if(condition.conditions) { conditional += ` <conditions> ${condition.conditions.map((con, i) => generateStep(idxs.concat([i]), con)).join('')} <add-condition style="display: inline-flex; justify-content: flex-start; position: relative; min-height: 60px; margin: 3px; align-items: center; border: 2px solid black; border-radius: 10px; padding: 5px;"> <img class="pointer-enabled skill-icon-xs mr-1" onclick="addGolbinRaiderStep(${JSON.stringify(idxs)})" src="${CDNDIR}assets/media/main/plus.svg"> </add-condition> </conditions>`; } if(condition.result) { conditional += generateResult(idxs, condition); } conditional += `</conditional>`; return conditional; } function generateValueCollection(idxs, condition, collectionIdx) { let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } return `<value-collection style="position: relative; margin: 3px; padding-right: 25px;"> <remove-value style="position: absolute; right: 0; height: 100%; width: 25px; display: flex; justify-content: center; align-items: center; align-self: center;"> <button type="button" class="btn-block-option" onclick="removeGolbinRaiderValueCollection(${JSON.stringify(idxs)}, ${collectionIdx})" aria-label="Close"> <i class="fa fa-fw fa-times"></i> </button> </remove-value> ${values.map((v, j) => generateValue(idxs, v.id, condition, collectionIdx)).join('')} </value-collection>`; } function generateValues(idxs, condition) { let valueStr = ``; let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } if(values.length > 0) { valueStr += `<values style="display: grid; grid-template-columns: 1fr; margin: 3px; padding: 5px; grid-auto-flow: row; grid-gap: 4px; ${golbinRaidComparisons[condition.comparison].collection ? `border: 2px solid black; border-radius: 10px;` : ``}">`; if(golbinRaidComparisons[condition.comparison].collection) { valueStr += condition.collection.map((val, i) => { return generateValueCollection(idxs, condition, i); }).join('') valueStr += `<add-value style="display: inline-flex; justify-content: flex-start; position: relative; margin: 3px; align-items: center;"> <img class="pointer-enabled skill-icon-xs mr-1" src="${CDNDIR}assets/media/main/plus.svg" onclick="addGolbinRaiderValueCollection(${JSON.stringify(idxs)})"> </add-value>`; } else { valueStr += values.map((val, i) => generateValue(idxs, val.id, condition)).join('') } valueStr += `</values>`; } return valueStr; } function generateComparison(idxs, condition) { let comparison = ` <comparison style="display: flex; align-items: center;"> ${generateDropdown(golbinRaidConditionals[condition.conditional].comparisons(condition), condition, ({comparison}) => golbinRaidComparisons[comparison].name, ({id, name}) => `<a class='dropdown-item pointer-enabled' onclick='updateGolbinRaiderComparison(${JSON.stringify(idxs)}, ${typeof id == 'number' || typeof id == 'boolean' ? id : `"${id}"`})'>${name}</a>`)}`; comparison += generateValues(idxs, condition); comparison += `</comparison>`; return comparison; } function generateResult(idxs, condition) { return ` <result style="display: flex; align-items: center; margin-left: auto; margin-right: 15px; padding-left: 10px;"> <span style="width: 40px; font-size: 36px; color: white;">-></span> ${generateDropdown(golbinRaidResults, condition, ({result}) => golbinRaidResults[result].name, ({id, name}) => `<a class='dropdown-item pointer-enabled' onclick='updateGolbinRaiderResult(${JSON.stringify(idxs)}, ${typeof id == 'number' || typeof id == 'boolean' ? id : `"${id}"`})'>${name}</a>`)} </result>`; } function generateParam(idxs, i, condition) { let param = golbinRaidConditionals[condition.conditional].params[i]; if(param.visible === undefined || param.visible(condition)) { if(param.type == "dropdown") { return ` <parameter> ${generateDropdown(param.values(condition), condition, (args, collection) => { let {[param.id]:result} = args; return param.content ? param.content(args, collection) : (collection.find(c => c.id == result) || collection.find(c => c.id == param.default)).name; }, (args) => { let { id, name } = args; return `<a class='dropdown-item pointer-enabled' onclick='updateGolbinRaiderParameter(${JSON.stringify(idxs)}, ${i}, ${typeof id == 'number' || typeof id == 'boolean' ? id : `"${id}"`})'>${param.render ? param.render(args) : name}</a>` } )} </parameter>`; } else { console.log("unknown param" + param.type); return ''; } } else { return '' } } function generateValue(idxs, id, condition, collectionIdx=-1) { let values = [...golbinRaidComparisons[condition.comparison].values(condition)]; if(golbinRaidConditionals[condition.conditional].values) { golbinRaidConditionals[condition.conditional].values(condition).forEach(val => { let idx = values.findIndex(v => v.id == val.id); if(idx > -1) values[idx] = val; }); } let value = values.find(val => val.id == id); let ret = ``; if(value.type == "dropdown") { ret += ` <value style="display: inline-block;"> ${generateDropdown(value.values(condition), collectionIdx > -1 ? condition.collection[collectionIdx] : condition, (args, collection) => { let {[value.id]:result} = args; return value.content ? value.content(args, collection) : collection[result].name; }, (args) => { let { id, name } = args; return `<a class='dropdown-item pointer-enabled' onclick='updateGolbinRaiderValue(${JSON.stringify(idxs)}, "${value.id}", ${typeof id == 'number' || typeof id == 'boolean' ? id : `"${id}"`}${collectionIdx > -1 ? `, ${collectionIdx}` : ''})'>${value.render ? value.render(args) : name}</a>` } )} </value>`; } else if(value.type == "number") { let result = condition[value.id]; ret += ` <value style="display: inline-block; width: 100px;"> <input type="number" min="0" class="form-control m-1" placeholder="" value="${result}" oninput='updateGolbinRaiderValue(${JSON.stringify(idxs)}, "${value.id}", this.value${collectionIdx > -1 ? `, ${collectionIdx}` : ''})'> </value>`; } else { console.log(`unknown value ${value.type}`); return ''; } return ret; } function generateStep(idxs, step) { return ` <step style="display: flex; justify-content: flex-start; position: relative; min-height: 60px; margin: 3px; align-items: center; border: 2px solid black; border-radius: 10px; padding: 15px;"> <remove-step style="align-self: flex-end; position: absolute; top: 0; right: 0; height: 25px; width: 25px; display: flex; justify-content: center; align-items: center;"> <button type="button" class="btn-block-option" onclick="removeGolbinRaiderStep(${JSON.stringify(idxs)})" aria-label="Close"> <i class="fa fa-fw fa-times"></i> </button> </remove-step> ${idxs.length == 1 ? `<step-number style="display: inline-block; font-size: 36px; line-height: 60px; height: 60px; color: white; min-width: 35px;">${idxs[idxs.length-1] + 1}</step-number>` : ``} ${generateConditional(idxs, step)} </step> `; } function generateSteps(steps) { return ` <steps style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: 0; overflow-y: auto;'> <sortable-steps> ${steps.map((step, i) => i != steps.length-1 ? generateStep([i], step) : '').join('')} </sortable-steps> <add-step style="display: inline-flex; justify-content: flex-start; position: relative; min-height: 60px; margin: 3px; align-items: center; border: 2px solid black; border-radius: 10px; padding: 5px;"> <img class="pointer-enabled skill-icon-xs mr-1" onclick="addGolbinRaiderStep()" src="${CDNDIR}assets/media/main/plus.svg"> </add-step> ${generateStep([steps.length-1], steps[steps.length-1])} </steps> `; } function generateSideBar() { return ` <sidebar style='position: fixed; right: -600px; top: 4rem; height: 90%; width: 600px; z-index: 999; transition: right 500ms ease, width 500ms ease; background-color: grey; border-radius: 10px;'> <button style='position: absolute; left: -40px; top: 50%; height: 50px; width: 40px; z-index: 999; background-color: #a9a9a9;' onclick='toggleGolbinRaiderSidebar();'>GR</button> <container style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: 10px; background-color: #404040; display: grid; grid-template-rows: 30px 30px auto; grid-template-columns: auto; border-radius: 10px;'> <stats style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; grid-area: 1 / 1 / 1 / 1; display: grid; grid-template-rows: auto; grid-template-columns: auto;'></stats> <navigation style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; grid-area: 2 / 1 / 2 / 1;'> <button class='history' onclick='showGolbinRaiderTab(0);'>History</button> <button class='priorities' onclick='showGolbinRaiderTab(1);'>Priorities</button> <button class='steps' onclick='showGolbinRaiderTab(2);'>Steps</button> <button class='modifiers' onclick='showGolbinRaiderTab(3);'>Modifiers</button> <button class='runes' onclick='showGolbinRaiderTab(4);'>Runes</button> <button class='weights' onclick='showGolbinRaiderTab(5);'>Weights</button> <button class='settings' onclick='showGolbinRaiderTab(6);'>Settings</button> </navigation> <tabs style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; grid-area: 3 / 1 / 3 / 1;'> <tab class='history' style='position: absolute; top: 0; left: 0; right: 0; bottom: 0;'> <log style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: 0; overflow-y: auto;'></log> </tab> <tab class='priorities d-none' style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: grid; grid-template-rows: 120px auto; grid-template-columns: auto; justify-items: center; align-items: center;'> ${generatePrioritiesTab()} </tab> <tab class='steps d-none' style='position: absolute; top: 0; left: 0; right: 0; bottom: 0;'> ${generateSteps(golbinRaiderSelectionSteps)} </tab> <tab class='modifiers d-none' style='position: absolute; top: 0; left: 0; right: 0; bottom: 0;'> ${generateModifiersTab()} </tab> <tab class='runes d-none' style='position: absolute; top: 0; left: 0; right: 0; bottom: 0;'> <span style='color: white;'>Coming Soon :)</span> </tab> <tab class='weights d-none' style='position: absolute; top: 0; left: 0; right: 0; bottom: 0;'> <span style='color: white;'>Coming Soon :)</span> </tab> <tab class='settings d-none'> <span style='color: white;'>Coming Soon :)</span> </tab> </tabs> </container> </sidebar>`; } function generateItemSearchModal() { return ` <div class="modal" id="modal-golbinraider-item-select" tabindex="-1" role="dialog" aria-labelledby="modal-block-extra-large" aria-modal="true" style="display: none;"> <div class="modal-dialog modal-xl" role="document" style="height:80%;"> <div class="modal-content"> <div class="block block-themed block-transparent mb-0"> <div class="block-header bg-primary-dark"> <h3 class="block-title"> Hey </h3> <div class="block-options"> <button type="button" class="btn-block-option" data-dismiss="modal" aria-label="Close"> <i class="fa fa-fw fa-times"></i> </button> </div> </div> <div class="block-content block-content-full"> <div class="col-12"> <div class="row" id="golbinraider-items-search"> <div class="col-12"> <input type="text" class="form-control form-control-lg py-4" id="golbinraider-item-search" name="golbinraider-item-search" placeholder="Search Items"> </div> <div id="golbinraider-items-list" class="col-12"> </div> </div> </div> </div> </div> </div> </div> </div> ` } function updateGolbinRaiderItemSearch(search) { let slot = $("#modal-golbinraider-item-select").get(0).dataset.slot; let index = $("#modal-golbinraider-item-select").get(0).dataset.index; const options = { shouldSort: true, tokenize: true, matchAllTokens: true, findAllMatches: true, threshold: 0, location: 0, distance: 100, maxPatternLength: 32, minMatchCharLength: 1, keys: ["name"], }; let slotItems = items.filter(item => item.validSlots && item.validSlots.includes(slot) && !RaidManager.bannedItems.includes(item.id) && (!golbinRaiderPriorities[slot].includes(item.id) || item.id == golbinRaiderPriorities[slot][index])); if(slot == CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive]) slotItems = slotItems.filter(item => !RaidManager.bannedPassiveItems.includes(item.id)) const fuse = new Fuse(slotItems, options); let result = fuse.search(search); if(search == '') result = slotItems; $('item-icon', $('#golbinraider-items-list').get(0)).toArray().forEach(el => { if(el._tippy) el._tippy.destroy(); }); $('#golbinraider-items-list').get(0).innerHTML = ''; $('#golbinraider-items-list').append(generateItemImage(-1, 0, false, true, slot)); $('#golbinraider-items-list').append(result.map(item => generateItemImage(item.id, 0, item.id == golbinRaiderPriorities[slot][index], false, slot)).join('')); $('item-icon', $('#golbinraider-items-list').get(0)).toArray().forEach(el => { el.setAttribute('onclick', `selectGolbinRaiderItemPriority('${slot}', ${index}, ${el.dataset.id})`); }); tippy($('item-icon', $('#golbinraider-items-list').get(0)).toArray(), { content: '', allowHTML: true, placement: "left", interactive: false, animation: false, onShow: itemOnShow, onHidden: itemOnHidden }); } function selectGolbinRaiderItemPriority(slot, index, id=-1) { golbinRaiderPriorities[slot][index] = id; golbinRaiderPriorities[slot] = golbinRaiderPriorities[slot].filter(id => id > -1); localStorage.setItem(`golbinRaiderPriorities`, JSON.stringify(golbinRaiderPriorities)); showGolbinRaiderPriority(slot); $("#modal-golbinraider-item-select").modal("hide"); } let sortableSteps = false; function updateSortableSteps() { if(sortableSteps) { sortableSteps.destroy(); sortableSteps = false; } sortableSteps = Sortable.create($('sidebar container tabs tab steps sortable-steps').get(0), { group: `golbinRaiderSteps`, draggable: "step", handle: 'step-number', onEnd: (evt) => { let start = Math.min(evt.newIndex, evt.oldIndex); let end = Math.max(evt.newIndex, evt.oldIndex); golbinRaiderSelectionSteps.splice(evt.newIndex, 0, golbinRaiderSelectionSteps.splice(evt.oldIndex, 1).pop()); for(let i=start; i<=end; i++) $('steps > sortable-steps > step').get(i).outerHTML = generateStep([i], golbinRaiderSelectionSteps[i]); triggerStepsSave(); }, onMove: function() { }, onChoose: function(evt) { }, }); } const sideBar = generateSideBar(); $('#page-container').append(sideBar); updateSortableSteps(); window.toggleGolbinRaiderSidebar = () => { let width = $('sidebar').get(0).style.getPropertyValue('width'); let right = $('sidebar').get(0).style.getPropertyValue('right'); $('sidebar').get(0).style.setProperty('right', right == '0px' ? `-${width}` : '0px'); } window.showGolbinRaiderTab = (i) => { $($('sidebar tabs tab').addClass('d-none').get(i)).removeClass('d-none'); if(i == 2) { $('sidebar').get(0).style.setProperty('width', '1200px'); } else { $('sidebar').get(0).style.setProperty('width', '600px'); } }; window.showGolbinRaiderPriority = showGolbinRaiderPriority; window.showGolbinRaiderItemSelect = showGolbinRaiderItemSelect; window.selectGolbinRaiderItemPriority = selectGolbinRaiderItemPriority; $('#page-container').append(generateItemSearchModal()); $("#golbinraider-item-search").keyup(function() { let search = $("#golbinraider-item-search").val(); updateGolbinRaiderItemSearch(search); }); let golbinLogStats = []; function addStat(updateFn) { golbinLogStats.push({el: document.createElement('stat'), updateFn: updateFn}); golbinLogStats[golbinLogStats.length-1].el.style.setProperty('grid-area', `1 / ${golbinLogStats.length} / 1 / ${golbinLogStats.length}`); golbinLogStats[golbinLogStats.length-1].el.style.setProperty('color', 'white'); golbinLogStats[golbinLogStats.length-1].el.style.setProperty('font-size', '12px'); golbinLogStats[golbinLogStats.length-1].el.style.setProperty('text-align', 'center'); $('stats').get(0).style.setProperty('grid-template-columns', golbinLogStats.map(s => 'auto').join(' ')); $('stats').append(golbinLogStats[golbinLogStats.length-1].el); } addStat(() => `Wave ${raidManager.wave+1}`); addStat(() => `${raidManager.waveProgress + 1} / ${raidManager.waveLength}`); //addStat(() => `${maxFood()} Max Food`); //addStat(() => `${maxAmmo()} Max Ammo`); //addStat(() => `${maxRunes()} Max Runes`); //addStat(() => `${raidManager.player.equipmentStats.damageReduction}% DR`); addStat(() => `${new Date((new Date().getTime() - raidManager.startTimestamp)).toISOString().substr(11, 8)}`); addStat(() => `${raidManager.coinsEarned} GC`); addStat(() => `${(raidManager.coinsEarned / ((new Date().getTime() - raidManager.startTimestamp)/1000)).toFixed(2)} GC/s`); function statTick() { if($('#page-header').get(0).classList.contains('bg-golbinraid') && $('sidebar button').get(0).classList.contains('d-none')) { $('sidebar button').get(0).classList.remove('d-none'); } else if(!$('#page-header').get(0).classList.contains('bg-golbinraid') && !$('sidebar button').get(0).classList.contains('d-none')) { $('sidebar button').get(0).classList.add('d-none'); } if(!game.isGolbinRaid) return; golbinLogStats.forEach(stat => stat.el.innerText = stat.updateFn()); } let __raidManagerStopCombat = raidManager.stopCombat.bind(raidManager); function _raidManagerStopCombat(fled=true) { raidManager.selectedDifficulty = raidManager._setDifficulty; __raidManagerStopCombat(...arguments); if(!fled) { setTimeout(() => { Swal.close(); raidManager.preStartRaid() }, 1000); } } raidManager.stopCombat = _raidManagerStopCombat.bind(raidManager); function restartCombat() { raidManager.selectedDifficulty = raidManager._setDifficulty; raidManager.stopCombat(true); setTimeout(() => { Swal.close(); raidManager.preStartRaid() }, 1000); } let __golbinTick = raidManager.tick.bind(raidManager); function _golbinTick() { __golbinTick(...arguments); try { if(raidManager.state == RaidState.FightingWave) { if(golbinRaiderSettings.autoHeal) { let enemyMaxHit = Math.max(...raidManager.enemy.availableAttacks.map(a => raidManager.enemy.getAttackMaxDamage(a.attack))) if(raidManager.player.hitpoints <= enemyMaxHit) { //console.log(`ALMOST DIED ${raidManager.player.hitpoints}hp, ${enemyMaxHit} max hit`); if(raidManager.player.hitpoints < raidManager.player.stats.maxHitpoints) raidManager.player.eatFood(); } } } if(!(raidManager.state === RaidState.Unstarted || raidManager.isPaused || !game.isGolbinRaid)) statTick(); } catch (e) { console.log(e); } } raidManager.tick = _golbinTick.bind(raidManager); let __fireRandomModifierSelection = raidManager.fireRandomModifierSelection.bind(raidManager); function _fireRandomModifierSelection() { //__fireRandomModifierSelection(...arguments); //modifierData //RaidManager.possibleModifiers const playerMods = new MappedModifiers(); playerMods.addArrayModifiers(this.randomPlayerModifiers); const golbinMods = new MappedModifiers(); golbinMods.addArrayModifiers(this.randomEnemyModifiers); let option = rollInteger(0, raidManager.randomModifiersBeingSelected.length-1); const modifiers = golbinRaiderModifierPriority[raidManager.isSelectingPositiveModifier ? 'positive' : 'negative']; const priorities = [...raidManager.randomModifiersBeingSelected].map(mod => modifiers.findIndex(m => m.key == mod.key)); const values = [...raidManager.randomModifiersBeingSelected].map(mod => { let modData = modifierData[mod.key] let v = 0; if(raidManager.isSelectingPositiveModifier) { v = (modData.isNegative ? golbinMods.standardModifiers.get(mod.key) : playerMods.standardModifiers.get(mod.key)) || 0 } else { v = (modData.isNegative ? playerMods.standardModifiers.get(mod.key) : golbinMods.standardModifiers.get(mod.key)) || 0 } if(modData.modifyValue) v = modData.modifyValue(v); return v; }) const underSoftCap = priorities.map((idx, i) => values[i] < modifiers[idx].soft || modifiers[idx].soft == 0); const underHardCap = priorities.map((idx, i) => values[i] < modifiers[idx].hard || modifiers[idx].hard == 0); for(let i=0; i<priorities.length; i++) { if(underHardCap[i]) { if(underHardCap[option]) { if(underSoftCap[i]) { if(underSoftCap[option]) { if(priorities[i] < priorities[option]) option = i; } else { option = i; } } } else { option = i; } } } raidManager.selectRandomModifier(option); } raidManager.fireRandomModifierSelection = _fireRandomModifierSelection.bind(raidManager); let __fireCategorySelectModal = raidManager.fireCategorySelectModal.bind(raidManager); function _fireCategorySelectModal() { //__fireCategorySelectModal(...arguments); let result, step; try { ({ result, step } = evaluateSteps(golbinRaiderSelectionSteps)); } catch (e) { console.log(e); } if(result == 'abort') { restartCombat(); return; } if(result == 'pause') { raidManager.pause(); return; } if(result == 'passive') { let currentRunes = availableRunes().map(id => [id, golbinItemCount(id)]); let currentItems = raidManager.player.equipment.slotArray.map(slot => { return { id: slot.item.id, qty: slot.quantity, isAlt: raidManager.player.altAttacks[slot.type].length > 0, altAttacks: raidManager.player.altAttacks[slot.type].map(alt => alt.id) }; }); let currentFood = { id: (items[raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.id] || {id: -1}).id, qty: raidManager.player.food.slots[raidManager.player.food.selectedSlot].quantity || 0 } raidManager.rerollPassiveCallback(); addChoice('passive', 0, [{ itemID: raidManager.player.equipment.slotArray[CONSTANTS.equipmentSlot.Passive].item.id, qty: 1 }], currentItems, currentRunes, currentFood); return; } if(result !== undefined && result != false) { raidManager.showEquipmentSelectionModal(result); return; } } raidManager.fireCategorySelectModal = _fireCategorySelectModal.bind(raidManager); let __fireItemSelectModal = raidManager.fireItemSelectModal.bind(raidManager); function _fireItemSelectModal() { //__fireItemSelectModal(...arguments); } raidManager.fireItemSelectModal = _fireItemSelectModal.bind(raidManager); let __setEquipmentSelection = raidManager.setEquipmentSelection.bind(raidManager); function _setEquipmentSelection(category) { __setEquipmentSelection(...arguments); let options = [...raidManager.itemsBeingSelected]; let availRunes = availableRunes(); let currentRunes = availableRunes().map(id => [id, golbinItemCount(id)]); let currentItems = raidManager.player.equipment.slotArray.map(slot => { if(slot.occupiedBy !== 'None') return { id: -1, qty: 0, isAlt: false, altAttacks: [] } return { id: slot.item.id, qty: slot.quantity, isAlt: raidManager.player.altAttacks[slot.type].length > 0, altAttacks: raidManager.player.altAttacks[slot.type].map(alt => alt.id) }; }); let currentFood = { id: (items[raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.id] || {id: -1}).id, qty: raidManager.player.food.slots[raidManager.player.food.selectedSlot].quantity || 0 } try { if(category == 'runes') { let option = options.findIndex(o => o.itemID == -1); for(let i = 0; i<availRunes.length; i++) { let rune = availRunes[i]; if(hasOceanSong && !haveRunes([[rune, 1]]) && options.findIndex(item => item.itemID == rune) != -1) option = options.findIndex(item => item.itemID == rune) } options[options.findIndex(o => o.itemID == -1)].itemID = CONSTANTS.item.Rune_Essence; if(options[option].itemID != CONSTANTS.item.Rune_Essence) { raidManager.addRunesCallback(options[option].itemID, options[option].qty) } else { raidManager.addExistingRunesCallback(options[option].qty) } addChoice(category, option, options, currentItems, currentRunes, currentFood); } else if (category == 'food') { options = options.map(option => { option.healing = items[option.itemID].healsFor * option.qty; if(option.itemID == raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.id) option.healing += raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.healsFor * raidManager.player.food.slots[raidManager.player.food.selectedSlot].quantity; return option; }); let option = -1; let currentHealing = raidManager.player.food.slots[raidManager.player.food.selectedSlot].item.healsFor * raidManager.player.food.slots[raidManager.player.food.selectedSlot].quantity; options.forEach((o, i) => { if(o.healing > currentHealing && (options[option] === undefined || o.healing > options[option].healing)) option = i; }); if(option > -1) { raidManager.addFoodCallback(options[option].itemID, options[option].qty); } else { raidManager.selectNothingCallback(); } addChoice(category, option, options, currentItems, currentRunes, currentFood); } else { options = options.map(option => { option.slots = items[option.itemID].validSlots.concat(items[option.itemID].occupiesSlots).filter(slot => slot != CONSTANTS.equipmentSlot[CONSTANTS.equipmentSlot.Passive]); option.weight = itemWeight(option.itemID, option.isAlt, items[option.itemID].validSlots[0]); option.diff = option.weight - option.slots.map(slot => itemWeight(raidManager.player.equipment.slotArray[CONSTANTS.equipmentSlot[slot]].item.id, raidManager.player.altAttacks[slot].length > 0, slot)).reduce((a,b) => a + b, 0); option.existingPriority = golbinRaiderPriorities[items[option.itemID].validSlots[0]].includes(raidManager.player.equipment.slotArray[CONSTANTS.equipmentSlot[items[option.itemID].validSlots[0]]].item.id) ? golbinRaiderPriorities[items[option.itemID].validSlots[0]].indexOf(raidManager.player.equipment.slotArray[CONSTANTS.equipmentSlot[items[option.itemID].validSlots[0]]].item.id) : -1 option.priority = golbinRaiderPriorities[items[option.itemID].validSlots[0]].includes(option.itemID) ? golbinRaiderPriorities[items[option.itemID].validSlots[0]].indexOf(option.itemID) : -1; return option; }); let option = -1; options.forEach((o, i) => { let priority = o.priority; let currentPriority = option > -1 ? options[option].priority : -1; let existingPriority = o.existingPriority; let diff = o.diff; let currentDiff = option > -1 ? options[option].diff : 0; if(priority != -1 && (existingPriority == -1 || priority < existingPriority) && (currentPriority == -1 || priority < currentPriority)) option = i; if(priority == existingPriority && priority == currentPriority && diff > currentDiff) option = i; }); if(option > -1) { raidManager.equipItemCallback(options[option].itemID, options[option].qty, options[option].isAlt); if(options[option].isAlt) options[option].altAttacks = raidManager.player.altAttacks[items[options[option].itemID].validSlots[0]].map(alt => alt.id); } else { raidManager.selectNothingCallback(); } addChoice(category, option, options, currentItems, currentRunes, currentFood); } } catch (e) { console.log(e); } options = null; currentRunes = null; } raidManager.setEquipmentSelection = _setEquipmentSelection.bind(raidManager); console.log('Melvor Golbin Raider Loaded'); } if(window.loadCombat) { let __loadCombat = window.loadCombat; window.loadCombat = function() { __loadCombat(); injectScript(script); } } else if (typeof unsafeWindow !== 'undefined' && unsafeWindow.loadCombat) { let __loadCombat = unsafeWindow.loadCombat; unsafeWindow.loadCombat = function() { __loadCombat(); injectScript(script); } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址