From 3e87ba04dbaa5933059ac774a15a18e4ad98cd5f Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 15:46:39 -0500 Subject: [PATCH 01/78] refactor to use classes and menu --- content.js | 426 -------- content/content.js | 466 +++++++++ content/maps/PokemonEvolutions.js | 481 +++++++++ content/maps/Pokemon_To_Id.js | 1086 ++++++++++++++++++++ content/maps/abilityMap.js | 315 ++++++ content/maps/natureMap.js | 29 + content/maps/weatherMap.js | 14 + content/util_classes/localStorage.util.js | 207 ++++ content/util_classes/pokemonMapper.util.js | 283 +++++ content/utils.js | 84 ++ fonts/pkmnems.ttf | Bin 0 -> 18164 bytes images/menu/1/center.png | Bin 0 -> 821 bytes images/menu/1/corner-bottom-left.png | Bin 0 -> 878 bytes images/menu/1/corner-bottom-right.png | Bin 0 -> 879 bytes images/menu/1/corner-top-left.png | Bin 0 -> 879 bytes images/menu/1/corner-top-right.png | Bin 0 -> 878 bytes images/menu/1/edge-bottom.png | Bin 0 -> 847 bytes images/menu/1/edge-left.png | Bin 0 -> 835 bytes images/menu/1/edge-right.png | Bin 0 -> 835 bytes images/menu/1/edge-top.png | Bin 0 -> 848 bytes images/menu/1/original.png | Bin 0 -> 640 bytes images/menu/2/center.png | Bin 0 -> 821 bytes images/menu/2/corner-bottom-left.png | Bin 0 -> 878 bytes images/menu/2/corner-bottom-right.png | Bin 0 -> 879 bytes images/menu/2/corner-top-left.png | Bin 0 -> 879 bytes images/menu/2/corner-top-right.png | Bin 0 -> 878 bytes images/menu/2/edge-bottom.png | Bin 0 -> 847 bytes images/menu/2/edge-left.png | Bin 0 -> 835 bytes images/menu/2/edge-right.png | Bin 0 -> 835 bytes images/menu/2/edge-top.png | Bin 0 -> 848 bytes images/menu/2/original.png | Bin 0 -> 657 bytes images/menu/3/center.png | Bin 0 -> 821 bytes images/menu/3/corner-bottom-left.png | Bin 0 -> 878 bytes images/menu/3/corner-bottom-right.png | Bin 0 -> 879 bytes images/menu/3/corner-top-left.png | Bin 0 -> 879 bytes images/menu/3/corner-top-right.png | Bin 0 -> 878 bytes images/menu/3/edge-bottom.png | Bin 0 -> 847 bytes images/menu/3/edge-left.png | Bin 0 -> 835 bytes images/menu/3/edge-right.png | Bin 0 -> 835 bytes images/menu/3/edge-top.png | Bin 0 -> 848 bytes images/menu/3/original.png | Bin 0 -> 671 bytes images/menu/4/center.png | Bin 0 -> 821 bytes images/menu/4/corner-bottom-left.png | Bin 0 -> 878 bytes images/menu/4/corner-bottom-right.png | Bin 0 -> 879 bytes images/menu/4/corner-top-left.png | Bin 0 -> 879 bytes images/menu/4/corner-top-right.png | Bin 0 -> 878 bytes images/menu/4/edge-bottom.png | Bin 0 -> 847 bytes images/menu/4/edge-left.png | Bin 0 -> 835 bytes images/menu/4/edge-right.png | Bin 0 -> 835 bytes images/menu/4/edge-top.png | Bin 0 -> 848 bytes images/menu/4/original.png | Bin 0 -> 659 bytes images/menu/5/center.png | Bin 0 -> 807 bytes images/menu/5/corner-bottom-left.png | Bin 0 -> 820 bytes images/menu/5/corner-bottom-right.png | Bin 0 -> 846 bytes images/menu/5/corner-top-left.png | Bin 0 -> 845 bytes images/menu/5/corner-top-right.png | Bin 0 -> 818 bytes images/menu/5/edge-bottom.png | Bin 0 -> 818 bytes images/menu/5/edge-left.png | Bin 0 -> 812 bytes images/menu/5/edge-right.png | Bin 0 -> 812 bytes images/menu/5/edge-top.png | Bin 0 -> 818 bytes images/menu/5/original.png | Bin 0 -> 629 bytes images/menu/labeling-script.sh | 56 + libs/crypto-js.min.js | 1 + manifest_chrome.json | 33 - options/generateSettingsUI.js | 45 + options/imageInjector.js | 54 + options/options.css | 207 ++++ options/options.html | 26 + options/options.js | 88 ++ options/optionsManager.js | 81 ++ options/settingsTemplate.js | 35 + styles.css | 55 +- 72 files changed, 3593 insertions(+), 479 deletions(-) delete mode 100644 content.js create mode 100644 content/content.js create mode 100644 content/maps/PokemonEvolutions.js create mode 100644 content/maps/Pokemon_To_Id.js create mode 100644 content/maps/abilityMap.js create mode 100644 content/maps/natureMap.js create mode 100644 content/maps/weatherMap.js create mode 100644 content/util_classes/localStorage.util.js create mode 100644 content/util_classes/pokemonMapper.util.js create mode 100644 content/utils.js create mode 100644 fonts/pkmnems.ttf create mode 100755 images/menu/1/center.png create mode 100755 images/menu/1/corner-bottom-left.png create mode 100755 images/menu/1/corner-bottom-right.png create mode 100755 images/menu/1/corner-top-left.png create mode 100755 images/menu/1/corner-top-right.png create mode 100755 images/menu/1/edge-bottom.png create mode 100755 images/menu/1/edge-left.png create mode 100755 images/menu/1/edge-right.png create mode 100755 images/menu/1/edge-top.png create mode 100644 images/menu/1/original.png create mode 100644 images/menu/2/center.png create mode 100644 images/menu/2/corner-bottom-left.png create mode 100644 images/menu/2/corner-bottom-right.png create mode 100644 images/menu/2/corner-top-left.png create mode 100644 images/menu/2/corner-top-right.png create mode 100644 images/menu/2/edge-bottom.png create mode 100644 images/menu/2/edge-left.png create mode 100644 images/menu/2/edge-right.png create mode 100644 images/menu/2/edge-top.png create mode 100644 images/menu/2/original.png create mode 100755 images/menu/3/center.png create mode 100755 images/menu/3/corner-bottom-left.png create mode 100755 images/menu/3/corner-bottom-right.png create mode 100755 images/menu/3/corner-top-left.png create mode 100755 images/menu/3/corner-top-right.png create mode 100755 images/menu/3/edge-bottom.png create mode 100755 images/menu/3/edge-left.png create mode 100755 images/menu/3/edge-right.png create mode 100755 images/menu/3/edge-top.png create mode 100644 images/menu/3/original.png create mode 100644 images/menu/4/center.png create mode 100644 images/menu/4/corner-bottom-left.png create mode 100644 images/menu/4/corner-bottom-right.png create mode 100644 images/menu/4/corner-top-left.png create mode 100644 images/menu/4/corner-top-right.png create mode 100644 images/menu/4/edge-bottom.png create mode 100644 images/menu/4/edge-left.png create mode 100644 images/menu/4/edge-right.png create mode 100644 images/menu/4/edge-top.png create mode 100644 images/menu/4/original.png create mode 100755 images/menu/5/center.png create mode 100755 images/menu/5/corner-bottom-left.png create mode 100755 images/menu/5/corner-bottom-right.png create mode 100755 images/menu/5/corner-top-left.png create mode 100755 images/menu/5/corner-top-right.png create mode 100755 images/menu/5/edge-bottom.png create mode 100755 images/menu/5/edge-left.png create mode 100755 images/menu/5/edge-right.png create mode 100755 images/menu/5/edge-top.png create mode 100644 images/menu/5/original.png create mode 100755 images/menu/labeling-script.sh create mode 100644 libs/crypto-js.min.js delete mode 100644 manifest_chrome.json create mode 100644 options/generateSettingsUI.js create mode 100644 options/imageInjector.js create mode 100644 options/options.css create mode 100644 options/options.html create mode 100644 options/options.js create mode 100644 options/optionsManager.js create mode 100644 options/settingsTemplate.js diff --git a/content.js b/content.js deleted file mode 100644 index 6c14f6b..0000000 --- a/content.js +++ /dev/null @@ -1,426 +0,0 @@ -const runningStatusDiv = document.createElement('div') -runningStatusDiv.textContent = 'RogueDex is running!' -runningStatusDiv.classList.add('text-base') -runningStatusDiv.classList.add('running-status') -document.body.insertBefore(runningStatusDiv, document.body.firstChild) - -let wrapperDivPositions = { - 'enemies': { - 'top' : '0', - 'left': '0', - 'opacity': '100' - }, - 'allies': { - 'top': '0', - 'left': '0', - 'opacity': '100' - } -} - -let slotId = -1 -const saveKey = 'x0i2O7WRiANTqPmZ' -// Creates the main wrapper div -function createDiv() { - const mainWrapper = document.createElement("div"); - mainWrapper.className = "main-fixed"; - - // Create the table header row - const headerRow = document.createElement("div"); - headerRow.className = "header-row"; - headerRow.id = "headerRow"; - - const pokemonHeader = document.createElement("div"); - pokemonHeader.textContent = "Pokemon"; - headerRow.appendChild(pokemonHeader); - - const weaknessHeader = document.createElement("div"); - weaknessHeader.textContent = "Weakness"; - headerRow.appendChild(weaknessHeader); - - const resistanceHeader = document.createElement("div"); - resistanceHeader.textContent = "Resistance"; - headerRow.appendChild(resistanceHeader); - - const immunityHeader = document.createElement("div"); - immunityHeader.textContent = "Immunity"; - headerRow.appendChild(immunityHeader); - - mainWrapper.appendChild(headerRow); - return mainWrapper; -} - -function createEnemyDiv() { - const enemies = document.createElement("div"); - enemies.className = 'enemy-team' - enemies.id = "enemies"; - return enemies; -} - -function createAlliesDiv() { - const allies = document.createElement("div"); - allies.className = 'allies-team' - allies.id = "allies"; - return allies; -} - -// Enables drag-and-drop functionality on an element -function enableDragElement(elmnt) { - let pos1 = 0, - pos2 = 0, - pos3 = 0, - pos4 = 0; - const dragStartElement = elmnt; - - // Attach the mousedown event handler - dragStartElement.onmousedown = dragMouseDown; - - function dragMouseDown(e) { - e = e || window.event; - if (e.target.type === 'submit' || e.target.type === 'range') return - e.preventDefault(); - pos3 = e.clientX; - pos4 = e.clientY; - document.onmouseup = stopDragging; - document.onmousemove = dragElement; - } - - // Handles dragging movement - function dragElement(e) { - e = e || window.event; - if (e.target.type === 'submit' || e.target.type === 'range') return - e.preventDefault(); - pos1 = pos3 - e.clientX; - pos2 = pos4 - e.clientY; - pos3 = e.clientX; - pos4 = e.clientY; - elmnt.style.top = elmnt.offsetTop - pos2 + "px"; - elmnt.style.left = elmnt.offsetLeft - pos1 + "px"; - } - - // Stops dragging on mouse release - function stopDragging() { - document.onmouseup = null; - document.onmousemove = null; - } -} - -const enemiesDiv = createEnemyDiv() -const alliesDiv = createAlliesDiv() - -enableDragElement(enemiesDiv); -enableDragElement(alliesDiv); - -document.body.appendChild(enemiesDiv); -document.body.appendChild(alliesDiv); - -let Types -(function (Types) { - Types[Types["normal"] = 1] = 1; - Types[Types["fighting"] = 2] = 2; - Types[Types["flying"] = 3] = 3; - Types[Types["poison"] = 4] = 4; - Types[Types["ground"] = 5] = 5; - Types[Types["rock"] = 6] = 6; - Types[Types["bug"] = 7] = 7; - Types[Types["ghost"] = 8] = 8; - Types[Types["steel"] = 9] = 9; - Types[Types["fire"] = 10] = 10; - Types[Types["water"] = 11] = 11; - Types[Types["grass"] = 12] = 12; - Types[Types["electric"] = 13] = 13; - Types[Types["psychic"] = 14] = 14; - Types[Types["ice"] = 15] = 15; - Types[Types["dragon"] = 16] = 16; - Types[Types["dark"] = 17] = 17; - Types[Types["fairy"] = 18] = 18; -})(Types || (Types = {})); - -let Stat; -(function (Stat) { - Stat[Stat["HP"] = 0] = "HP"; - Stat[Stat["ATK"] = 1] = "ATK"; - Stat[Stat["DEF"] = 2] = "DEF"; - Stat[Stat["SPATK"] = 3] = "SPATK"; - Stat[Stat["SPDEF"] = 4] = "SPDEF"; - Stat[Stat["SPD"] = 5] = "SPD"; -})(Stat || (Stat = {})); -; - -function createTooltipDiv(tip) { - const tooltip = document.createElement('div') - tooltip.classList.add('text-base') - tooltip.classList.add('tooltiptext') - tooltip.textContent = tip - return tooltip -} - -// Current values: weaknesses, resistances, immunities -function createTypeEffectivenessWrapper(effectiveness, types) { - const typeEffectivenessWrapper = document.createElement('div') - typeEffectivenessWrapper.classList.add(`pokemon-${effectiveness}`); - typeEffectivenessWrapper.classList.add('tooltip'); - let counter = 0; - let block = document.createElement('div'); - typeEffectivenessWrapper.appendChild(block) - types.forEach(type => { - if (counter % 3 === 0) { - block = document.createElement('div'); - typeEffectivenessWrapper.appendChild(block) - } - const typeIcon = document.createElement('div'); - typeIcon.style.backgroundImage = `url('https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/types/generation-viii/sword-shield/${Types[type]}.png')`; - typeIcon.className = 'type-icon'; - block.appendChild(typeIcon) - counter += 1; - }); - return typeEffectivenessWrapper -} - -let currentEnemyPage = 0; -let currentAllyPage = 0; -let enemiesPokemon = []; -let alliesPokemon = []; -let weather = {}; - -function createArrowButtonsDiv(divId) { - const buttonsDiv = document.createElement('div') - buttonsDiv.classList.add('arrow-button-wrapper') - const arrowUpButton = document.createElement('button') - const arrowDownButton = document.createElement('button') - arrowUpButton.classList.add('text-base') - arrowDownButton.classList.add('text-base') - arrowUpButton.classList.add('arrow-button') - arrowDownButton.classList.add('arrow-button') - arrowUpButton.textContent = "↑" - arrowDownButton.textContent = "↓" - arrowUpButton.id = `${divId}-up` - arrowDownButton.id = `${divId}-down` - arrowUpButton.addEventListener('click', changePage) - arrowDownButton.addEventListener('click', changePage) - buttonsDiv.appendChild(arrowUpButton) - buttonsDiv.appendChild(arrowDownButton) - return buttonsDiv -} - -function createOpacitySliderDiv(divId, initialValue = "100") { - const sliderDiv = document.createElement('div') - sliderDiv.classList.add('slider-wrapper') - const opacityTextDiv = document.createElement('div') - opacityTextDiv.classList.add('text-base') - opacityTextDiv.textContent = "Opacity:" - const slider = document.createElement('input') - slider.type = "range" - slider.min = "10" - slider.max = "100" - slider.value = initialValue - slider.id = `${divId}-slider` - sliderDiv.appendChild(opacityTextDiv) - sliderDiv.appendChild(slider) - sliderDiv.addEventListener('input', changeOpacity) - return sliderDiv -} - -function changeOpacity(e) { - const divId = e.target.id.split("-")[0] - const div = document.getElementById(divId) - wrapperDivPositions[divId].opacity = e.target.value - div.style.opacity = `${e.target.value / 100}` -} - -function changePage(click) { - const buttonId = click.target.id - const divId = buttonId.split("-")[0] - const direction = buttonId.split("-")[1] - if (direction === 'up') { - if (divId === 'enemies') { - if (currentEnemyPage > 0) { - currentEnemyPage -= 1 - } else { - currentEnemyPage = enemiesPokemon.length - 1 - } - } else if (divId === 'allies') { - if (currentAllyPage > 0) { - currentAllyPage -= 1 - } else { - currentAllyPage = alliesPokemon.length - 1 - } - } - } else if (direction === 'down') { - if (divId === 'enemies') { - if ((currentEnemyPage + 1) < enemiesPokemon.length) { - currentEnemyPage += 1 - } else { - currentEnemyPage = 0 - } - } else if (divId === 'allies') { - if ((currentAllyPage + 1) < alliesPokemon.length) { - currentAllyPage += 1 - } else { - currentAllyPage = 0 - } - } - } - createCardsDiv(divId) -} - -function createPokemonCardDiv(divId, pokemon) { - const card = document.createElement('div'); - card.classList.add('pokemon-card'); - - const opacitySliderDiv = createOpacitySliderDiv(divId, wrapperDivPositions[divId].opacity) - - const infoRow = document.createElement('div'); - infoRow.style.display = 'flex'; - - const iconWrapper = document.createElement('div'); - iconWrapper.className = 'pokemon-icon'; - const icon = document.createElement('img'); - icon.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; - iconWrapper.appendChild(icon); - infoRow.appendChild(iconWrapper); - - const weaknessesWrapper = createTypeEffectivenessWrapper('weaknesses', pokemon.typeEffectiveness.weaknesses) - weaknessesWrapper.appendChild(createTooltipDiv('Weak to')) - - const resistancesWrapper = createTypeEffectivenessWrapper('resistances', pokemon.typeEffectiveness.resistances) - resistancesWrapper.appendChild(createTooltipDiv('Resists')) - - const immunitiesWrapper = createTypeEffectivenessWrapper('immunities', pokemon.typeEffectiveness.immunities) - immunitiesWrapper.appendChild(createTooltipDiv('Immune to')) - - infoRow.appendChild(weaknessesWrapper) - infoRow.appendChild(resistancesWrapper) - infoRow.appendChild(immunitiesWrapper) - - const extraInfoRow = document.createElement('div'); - extraInfoRow.classList.add('text-base') - extraInfoRow.textContent = `Ability: ${pokemon.ability} - Nature: ${pokemon.nature}`; - - const ivsRow = document.createElement('div'); - ivsRow.classList.add('text-base'); - ivsRow.textContent = `HP: ${pokemon.ivs[Stat["HP"]]}, ATK: ${pokemon.ivs[Stat["ATK"]]}, DEF: ${pokemon.ivs[Stat["DEF"]]}, SPE: ${pokemon.ivs[Stat["SPD"]]}, SPD: ${pokemon.ivs[Stat["SPDEF"]]}, SPA: ${pokemon.ivs[Stat["SPATK"]]}`; - - let weatherRow = undefined - if (weather.type && weather.turnsLeft) { - weatherRow = document.createElement('div'); - weatherRow.classList.add('text-base'); - weatherRow.textContent = `Weather: ${weather.type}, Turns Left: ${weather.turnsLeft}` - } - - card.appendChild(opacitySliderDiv) - card.appendChild(infoRow) - card.appendChild(extraInfoRow) - card.appendChild(ivsRow) - if (weatherRow) { - card.appendChild(weatherRow) - } - return card -} - -function createWrapperDiv(divId) { - const oldDiv = document.getElementById(divId) - if (oldDiv) { - wrapperDivPositions[divId].top = oldDiv.style.top; - wrapperDivPositions[divId].left = oldDiv.style.left; - oldDiv.remove(); - } - const newDiv = divId === 'enemies' ? createEnemyDiv() : createAlliesDiv() - enableDragElement(newDiv) - newDiv.style.top = wrapperDivPositions[divId].top - newDiv.style.left = wrapperDivPositions[divId].left - newDiv.style.opacity = "" + (Number(wrapperDivPositions[divId].opacity) / 100) - return newDiv; -} - -function createCardsDiv(divId) { - let newDiv = createWrapperDiv(divId) - let buttonsDiv = createArrowButtonsDiv(divId) - newDiv.appendChild(buttonsDiv) - let pokemon = {} - if (divId === 'enemies') { - if (currentEnemyPage >= enemiesPokemon.length) currentEnemyPage = enemiesPokemon.length - 1 - pokemon = enemiesPokemon[currentEnemyPage] - } - else { - if (currentAllyPage >= alliesPokemon.length) currentAllyPage = alliesPokemon.length - 1 - pokemon = alliesPokemon[currentAllyPage] - } - const pokemonCards = document.createElement("div"); - pokemonCards.className = "pokemon-cards" - const card = createPokemonCardDiv(divId, pokemon) - pokemonCards.appendChild(card); - newDiv.appendChild(pokemonCards) - document.body.appendChild(newDiv) - return newDiv -} - -function deleteWrapperDivs() { - try { - ['allies', 'enemies'].forEach((divId) => { - const div = document.getElementById(divId) - wrapperDivPositions[divId].top = div.style.top - wrapperDivPositions[divId].left = div.style.left - document.body.removeChild(div) - }) - } catch (e) { - console.error(e) - } - -} - -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - console.log("Got message:", message, "from", sender, "current message:", document.getElementById('touchControls').getAttribute('data-ui-mode')) - const uiMode = touchControlsElement.getAttribute('data-ui-mode') - console.log("Current ui mode: ", uiMode) - if (message.type === 'UPDATE_ENEMIES_DIV' || message.type === 'UPDATE_ALLIES_DIV') { - slotId = message.slotId - if ( uiMode === 'TITLE' || uiMode === 'SAVE_SLOT') return sendResponde({ success: true }) - let divId = message.type === 'UPDATE_ENEMIES_DIV' ? 'enemies' : 'allies' - if (message.type === 'UPDATE_ENEMIES_DIV') { - enemiesPokemon = message.pokemon - } - else { - alliesPokemon = message.pokemon - } - weather = message.weather; - if (weather.turnsLeft === 0) weather.turnsLeft = 'N/A' - createCardsDiv(divId) - sendResponse({ success: true }); - } -}); - -const touchControlsElement = document.getElementById('touchControls') -if (touchControlsElement) { - const observer = new MutationObserver((mutations) => { - mutations.forEach(async (mutation) => { - if (mutation.type === 'attributes' && mutation.attributeName === 'data-ui-mode') { - const newValue = touchControlsElement.getAttribute('data-ui-mode'); - console.log('New data-ui-mode:', newValue); - if(newValue === "MESSAGE" || newValue === "COMMAND" || newValue === "CONFIRM") { - let currentSessionData = {} - for (key in localStorage) { - if ((slotId > 0 && key.includes(`sessionData${slotId}`)) || key.includes('sessionData')) { - currentSessionData = localStorage.getItem(key) - break - } - } - currentSessionData = JSON.parse(CryptoJS.AES.decrypt(currentSessionData, saveKey).toString(CryptoJS.enc.Utf8)) - console.log("Got session data", currentSessionData, "for slot id", slotId) - browserApi.runtime.sendMessage({ type: 'BG_GET_SAVEDATA', data: currentSessionData, slotId: slotId }) - } - if(newValue === "SAVE_SLOT") { - setTimeout(function() { - for (key in localStorage) { - if (key.includes('sessionData')) localStorage.removeItem(key) - } - }, 1000) - } - if(newValue === "SAVE_SLOT" || newValue === "TITLE" || newValue === "MODIFIER_SELECT" || newValue === "STARTER_SELECT") { - deleteWrapperDivs() - } - } - }); - }); - - observer.observe(touchControlsElement, { attributes: true }); -} \ No newline at end of file diff --git a/content/content.js b/content/content.js new file mode 100644 index 0000000..2eb6a06 --- /dev/null +++ b/content/content.js @@ -0,0 +1,466 @@ +// import CryptoJS from '../libs/crypto-js.min.js'; +// import Utils from "./utils.js"; + +const runningStatusDiv = document.createElement('div') +runningStatusDiv.textContent = 'RogueDex is running!' +runningStatusDiv.classList.add('text-base') +runningStatusDiv.classList.add('running-status') +document.body.insertBefore(runningStatusDiv, document.body.firstChild); +scriptInjector(); + +function scriptInjector() { + const scriptElem = document.createElement("script"); + scriptElem.src = chrome.runtime.getURL("/content/utils.js"); + scriptElem.type = "module"; + document.head.appendChild(scriptElem); + scriptElem.addEventListener("load", initUtilities); +} + +let Utils; + +function initUtilities(e) { + Utils = new UtilsClass(); + Utils.init(); + Utils.addEventListener('isReadyChange', () => { + if (Utils.isReady) { + console.log("All Scripts Loaded!") + touchControlListener(); + extensionSettingsListener(); + } else { + console.log("Error Loading Scripts :(") + } + //console.log(`isReady has changed to: ${Utils.isReady}`); + // Additional logic to handle the change + }); +} + +let wrapperDivPositions = { + 'enemies': { + 'top': '0', + 'left': '0', + 'opacity': '100' + }, + 'allies': { + 'top': '0', + 'left': '0', + 'opacity': '100' + } +} + +function createEnemyDiv() { + const enemies = document.createElement("div"); + enemies.className = 'enemy-team' + enemies.id = "enemies"; + return enemies; +} + +function createAlliesDiv() { + const allies = document.createElement("div"); + allies.className = 'allies-team' + allies.id = "allies"; + return allies; +} + +// Enables drag-and-drop functionality on an element +function enableDragElement(elmnt) { + let pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + const dragStartElement = elmnt; + + // Attach the mousedown event handler + dragStartElement.onmousedown = dragMouseDown; + + function dragMouseDown(e) { + e = e || window.event; + if (e.target.type === 'submit' || e.target.type === 'range') return + e.preventDefault(); + pos3 = e.clientX; + pos4 = e.clientY; + document.onmouseup = stopDragging; + document.onmousemove = dragElement; + } + + // Handles dragging movement + function dragElement(e) { + e = e || window.event; + if (e.target.type === 'submit' || e.target.type === 'range') return + e.preventDefault(); + pos1 = pos3 - e.clientX; + pos2 = pos4 - e.clientY; + pos3 = e.clientX; + pos4 = e.clientY; + elmnt.style.top = elmnt.offsetTop - pos2 + "px"; + elmnt.style.left = elmnt.offsetLeft - pos1 + "px"; + } + + // Stops dragging on mouse release + function stopDragging() { + document.onmouseup = null; + document.onmousemove = null; + } +} + +const enemiesDiv = createEnemyDiv() +const alliesDiv = createAlliesDiv() + +enableDragElement(enemiesDiv); +enableDragElement(alliesDiv); + +document.body.appendChild(enemiesDiv); +document.body.appendChild(alliesDiv); + +let Types +(function (Types) { + Types[Types["normal"] = 1] = 1; + Types[Types["fighting"] = 2] = 2; + Types[Types["flying"] = 3] = 3; + Types[Types["poison"] = 4] = 4; + Types[Types["ground"] = 5] = 5; + Types[Types["rock"] = 6] = 6; + Types[Types["bug"] = 7] = 7; + Types[Types["ghost"] = 8] = 8; + Types[Types["steel"] = 9] = 9; + Types[Types["fire"] = 10] = 10; + Types[Types["water"] = 11] = 11; + Types[Types["grass"] = 12] = 12; + Types[Types["electric"] = 13] = 13; + Types[Types["psychic"] = 14] = 14; + Types[Types["ice"] = 15] = 15; + Types[Types["dragon"] = 16] = 16; + Types[Types["dark"] = 17] = 17; + Types[Types["fairy"] = 18] = 18; +})(Types || (Types = {})); + +let Stat; +(function (Stat) { + Stat[Stat["HP"] = 0] = "HP"; + Stat[Stat["ATK"] = 1] = "ATK"; + Stat[Stat["DEF"] = 2] = "DEF"; + Stat[Stat["SPATK"] = 3] = "SPATK"; + Stat[Stat["SPDEF"] = 4] = "SPDEF"; + Stat[Stat["SPD"] = 5] = "SPD"; +})(Stat || (Stat = {})); +; + +function createTooltipDiv(tip) { + const tooltip = document.createElement('div') + tooltip.classList.add('text-base') + tooltip.classList.add('tooltiptext') + tooltip.textContent = tip + return tooltip +} + +// Current values: weaknesses, resistances, immunities +function createTypeEffectivenessWrapper(effectiveness, types) { + const typeEffectivenessWrapper = document.createElement('div') + typeEffectivenessWrapper.classList.add(`pokemon-${effectiveness}`); + typeEffectivenessWrapper.classList.add('tooltip'); + let counter = 0; + let block = document.createElement('div'); + typeEffectivenessWrapper.appendChild(block) + types.forEach(type => { + if (counter % 3 === 0) { + block = document.createElement('div'); + typeEffectivenessWrapper.appendChild(block) + } + const typeIcon = document.createElement('div'); + typeIcon.style.backgroundImage = `url('https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/types/generation-viii/sword-shield/${Types[type]}.png')`; + typeIcon.className = 'type-icon'; + block.appendChild(typeIcon) + counter += 1; + }); + return typeEffectivenessWrapper +} + +const pages = { + "enemies": 0, + "allies": 0, +} +const partySize = { + "enemies": 0, + "allies": 0 +} +let currentEnemyPage = 0; +let currentAllyPage = 0; +let enemiesPokemon = []; +let alliesPokemon = []; +let weather = {}; + +function createArrowButtonsDiv(divId) { + const buttonsDiv = document.createElement('div') + buttonsDiv.classList.add('arrow-button-wrapper') + const arrowUpButton = document.createElement('button') + const arrowDownButton = document.createElement('button') + arrowUpButton.classList.add('text-base') + arrowDownButton.classList.add('text-base') + arrowUpButton.classList.add('arrow-button') + arrowDownButton.classList.add('arrow-button') + arrowUpButton.textContent = "↑" + arrowDownButton.textContent = "↓" + arrowUpButton.id = `${divId}-up` + arrowDownButton.id = `${divId}-down` + arrowUpButton.addEventListener('click', changePage) + arrowDownButton.addEventListener('click', changePage) + buttonsDiv.appendChild(arrowUpButton) + buttonsDiv.appendChild(arrowDownButton) + return buttonsDiv +} + +function createOpacitySliderDiv(divId, initialValue = "100") { + const sliderDiv = document.createElement('div') + sliderDiv.classList.add('slider-wrapper') + const opacityTextDiv = document.createElement('div') + opacityTextDiv.classList.add('text-base') + opacityTextDiv.textContent = "Opacity:" + const slider = document.createElement('input') + slider.type = "range" + slider.min = "10" + slider.max = "100" + slider.value = initialValue + slider.id = `${divId}-slider` + sliderDiv.appendChild(opacityTextDiv) + sliderDiv.appendChild(slider) + sliderDiv.addEventListener('input', changeOpacity) + return sliderDiv +} + +function changeOpacity(e) { + const divId = e.target.id.split("-")[0] + const div = document.getElementById(divId) + wrapperDivPositions[divId].opacity = e.target.value + div.style.opacity = `${e.target.value / 100}` +} + +async function changePage(click) { + const buttonId = click.target.id + const divId = buttonId.split("-")[0] + const direction = buttonId.split("-")[1] + if (direction === 'up') { + if(pages[divId] > 0){ + pages[divId] -= 1 + } + else{ + pages[divId] = partySize[divId] + } + } else if (direction === 'down') { + if(pages[divId] < partySize[divId]) { + pages[divId] += 1 + } + else{ + pages[divId] = partySize[divId] + } + } + let sessionData = Utils.LocalStorage.getSessionData(); + await initCreation(sessionData); +} + +async function createPokemonCardDiv(divId, pokemon) { + console.log(pokemon); + const card = document.createElement('div'); + card.classList.add('pokemon-card'); + + const opacitySliderDiv = createOpacitySliderDiv(divId, wrapperDivPositions[divId].opacity) + + const infoRow = document.createElement('div'); + infoRow.style.display = 'flex'; + + const iconWrapper = document.createElement('div'); + iconWrapper.className = 'pokemon-icon'; + const icon = document.createElement('img'); + icon.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; + iconWrapper.appendChild(icon); + infoRow.appendChild(iconWrapper); + + console.log(pokemon); + const weaknessesWrapper = createTypeEffectivenessWrapper('weaknesses', pokemon.typeEffectiveness.weaknesses) + weaknessesWrapper.appendChild(createTooltipDiv('Weak to')) + + const resistancesWrapper = createTypeEffectivenessWrapper('resistances', pokemon.typeEffectiveness.resistances) + resistancesWrapper.appendChild(createTooltipDiv('Resists')) + + const immunitiesWrapper = createTypeEffectivenessWrapper('immunities', pokemon.typeEffectiveness.immunities) + immunitiesWrapper.appendChild(createTooltipDiv('Immune to')) + + infoRow.appendChild(weaknessesWrapper) + infoRow.appendChild(resistancesWrapper) + infoRow.appendChild(immunitiesWrapper) + + const extraInfoRow = document.createElement('div'); + extraInfoRow.classList.add('text-base') + extraInfoRow.textContent = `Ability: ${pokemon.ability} - Nature: ${pokemon.nature}`; + + const ivsRow = document.createElement('div'); + ivsRow.classList.add('text-base'); + ivsRow.textContent = `HP: ${pokemon.ivs[Stat["HP"]]}, ATK: ${pokemon.ivs[Stat["ATK"]]}, DEF: ${pokemon.ivs[Stat["DEF"]]}, SPE: ${pokemon.ivs[Stat["SPD"]]}, SPD: ${pokemon.ivs[Stat["SPDEF"]]}, SPA: ${pokemon.ivs[Stat["SPATK"]]}`; + + let weatherRow = undefined + if (weather.type && weather.turnsLeft) { + weatherRow = document.createElement('div'); + weatherRow.classList.add('text-base'); + weatherRow.textContent = `Weather: ${weather.type}, Turns Left: ${weather.turnsLeft}` + } + + card.appendChild(opacitySliderDiv) + card.appendChild(infoRow) + card.appendChild(extraInfoRow) + card.appendChild(ivsRow) + if (weatherRow) { + card.appendChild(weatherRow) + } + return card +} + +function createWrapperDiv(divId) { + const oldDiv = document.getElementById(divId) + if (oldDiv) { + wrapperDivPositions[divId].top = oldDiv.style.top; + wrapperDivPositions[divId].left = oldDiv.style.left; + oldDiv.remove(); + } + const newDiv = divId === 'enemies' ? createEnemyDiv() : createAlliesDiv() + enableDragElement(newDiv) + newDiv.style.top = wrapperDivPositions[divId].top + newDiv.style.left = wrapperDivPositions[divId].left + newDiv.style.opacity = "" + (Number(wrapperDivPositions[divId].opacity) / 100) + return newDiv; +} + +async function createCardsDiv(divId, pokemon) { + let newDiv = createWrapperDiv(divId) + let buttonsDiv = createArrowButtonsDiv(divId) + newDiv.appendChild(buttonsDiv) + const pokemonCards = document.createElement("div"); + pokemonCards.className = "pokemon-cards" + const card = await createPokemonCardDiv(divId, pokemon); + pokemonCards.appendChild(card); + newDiv.appendChild(pokemonCards) + document.body.appendChild(newDiv) + return newDiv +} + + +function deleteAllChildren(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +function deleteWrapperDivs() { + try { + console.log("DELETE CALLED") + // ['allies', 'enemies'].forEach((divId) => { + const enemies = document.getElementById("enemies"); + deleteAllChildren(enemies); + const allies = document.getElementById("allies"); + deleteAllChildren(enemies); + // wrapperDivPositions[divId].top = div.style.top + // wrapperDivPositions[divId].left = div.style.left + // document.body.removeChild(div) + // }) + } catch (e) { + console.error(e) + } +} + + +async function scaleElements() { + const data = await browserApi.storage.sync.get('scaleFactor'); + const scaleFactorMulti = data.scaleFactor || 1; + const baseWidth = 1920; // Assume a base width of 1920 pixels + const baseHeight = 1080; // Assume a base height of 1080 pixels + const currentWidth = window.innerWidth; + const currentHeight = window.innerHeight; + const scaleFactor_width = currentWidth / baseWidth; + const scaleFactor_height = currentHeight / baseHeight; + let scaleFactor = scaleFactor_width < scaleFactor_height ? scaleFactor_width : scaleFactor_height; + const enemiesDiv = document.getElementById('enemies'); + const alliesDiv = document.getElementById('allies'); + enemiesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; + alliesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; +} +async function initCreation(sessionData) { + deleteWrapperDivs(); + let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); + if (extensionSettings.showEnemies) { + await dataMapping("enemyParty", "enemies", sessionData); + } + if(extensionSettings.showParty){ + await dataMapping("party", "allies", sessionData); + } +} + +async function dataMapping(pokemonLocation, divId, sessionData){ + await Utils.PokeMapper.getPokemonArray(sessionData[pokemonLocation], sessionData.arena).then(async (pokemonData) => { + weather = pokemonData.hasOwnProperty('weather') ? pokemonData.weather : null; + partySize[divId] = pokemonData.pokemon.length; + let pIndex = determinePage(divId, pokemonData.pokemon); + await createCardsDiv(divId, pokemonData.pokemon[pIndex]).then(() => { + scaleElements(); + }); + }); +} + +function determinePage(divId, pokemon){ + if(pages[divId] >= pokemon.length){ + pages[divId] = pokemon.length - 1; + return pages[divId]; + } + else{ + return pages[divId]; + } +} + +function extensionSettingsListener(){ + browserApi.storage.onChanged.addListener(async function (changes, namespace) { + for (let [key, {oldValue, newValue}] of Object.entries(changes)) { + if (key === 'showMinified') { + let sessionData = Utils.LocalStorage.getSessionData(); + await initCreation(sessionData); + } + if (key === 'scaleFactor') { + await scaleElements(); + } + if (key === 'showEnemies') { + let sessionData = Utils.LocalStorage.getSessionData(); + await initCreation(sessionData); + } + if (key === 'showParty') { + let sessionData = Utils.LocalStorage.getSessionData(); + await initCreation(sessionData); + } + } + }); +} + + + +function touchControlListener() { + const touchControlsElement = document.getElementById('touchControls') + if (touchControlsElement) { + const observer = new MutationObserver((mutations) => { + mutations.forEach(async (mutation) => { + if (mutation.type === 'attributes' && mutation.attributeName === 'data-ui-mode') { + const newValue = touchControlsElement.getAttribute('data-ui-mode'); + console.log('New data-ui-mode:', newValue); + if (newValue === "MESSAGE" || newValue === "COMMAND" || newValue === "CONFIRM") { + Utils.LocalStorage.setSessionData(); + let sessionData = Utils.LocalStorage.getSessionData(); + await initCreation(sessionData); + } + if (newValue === "SAVE_SLOT") { + Utils.LocalStorage.clearAllSessionData(); + } + if (newValue === "SAVE_SLOT" || newValue === "TITLE" || newValue === "MODIFIER_SELECT" || newValue === "STARTER_SELECT") { + deleteWrapperDivs() + } + } + }); + }); + + window.addEventListener('resize', scaleElements); + observer.observe(touchControlsElement, {attributes: true}); + } +} + diff --git a/content/maps/PokemonEvolutions.js b/content/maps/PokemonEvolutions.js new file mode 100644 index 0000000..640c792 --- /dev/null +++ b/content/maps/PokemonEvolutions.js @@ -0,0 +1,481 @@ +window["__EvolutionMap"] = { + BULBASAUR: {name: "IVYSAUR", val: 16}, + IVYSAUR: {name: "VENUSAUR", val: 32}, + CHARMANDER: {name: "CHARMELEON", val: 16}, + CHARMELEON: {name: "CHARIZARD", val: 36}, + SQUIRTLE: {name: "WARTORTLE", val: 16}, + WARTORTLE: {name: "BLASTOISE", val: 36}, + CATERPIE: {name: "METAPOD", val: 7}, + METAPOD: {name: "BUTTERFREE", val: 10}, + WEEDLE: {name: "KAKUNA", val: 7}, + KAKUNA: {name: "BEEDRILL", val: 10}, + PIDGEY: {name: "PIDGEOTTO", val: 18}, + PIDGEOTTO: {name: "PIDGEOT", val: 36}, + RATTATA: {name: "RATICATE", val: 20}, + SPEAROW: {name: "FEAROW", val: 20}, + EKANS: {name: "ARBOK", val: 22}, + SANDSHREW: {name: "SANDSLASH", val: 22}, + NIDORAN_F: {name: "NIDORINA", val: 16}, + NIDORAN_M: {name: "NIDORINO", val: 16}, + ZUBAT: {name: "GOLBAT", val: 22}, + ODDISH: {name: "GLOOM", val: 21}, + PARAS: {name: "PARASECT", val: 24}, + VENONAT: {name: "VENOMOTH", val: 31}, + DIGLETT: {name: "DUGTRIO", val: 26}, + MEOWTH: {name: "PERSIAN", val: 28}, + PSYDUCK: {name: "GOLDUCK", val: 33}, + MANKEY: {name: "PRIMEAPE", val: 28}, + POLIWAG: {name: "POLIWHIRL", val: 25}, + ABRA: {name: "KADABRA", val: 16}, + MACHOP: {name: "MACHOKE", val: 28}, + BELLSPROUT: {name: "WEEPINBELL", val: 21}, + TENTACOOL: {name: "TENTACRUEL", val: 30}, + GEODUDE: {name: "GRAVELER", val: 25}, + PONYTA: {name: "RAPIDASH", val: 40}, + SLOWPOKE: [{name: "SLOWBRO", val: 37}, {name: "SLOWKING", val: 1}], + MAGNEMITE: {name: "MAGNETON", val: 30}, + DODUO: {name: "DODRIO", val: 31}, + SEEL: {name: "DEWGONG", val: 34}, + GRIMER: {name: "MUK", val: 38}, + GASTLY: {name: "HAUNTER", val: 25}, + DROWZEE: {name: "HYPNO", val: 26}, + KRABBY: {name: "KINGLER", val: 28}, + VOLTORB: {name: "ELECTRODE", val: 30}, + CUBONE: [{name: "ALOLA_MAROWAK", val: 28}, {name: "MAROWAK", val: 28}], + TYROGUE: [{name: "HITMONLEE", val: 20},{name: "HITMONCHAN", val: 20}, {name: "HITMONTOP", val: 20}], + KOFFING: [{name: "WEEZING", val: 35}, {name: "GALAR_WEEZING", val: 35}], + RHYHORN: {name: "RHYDON", val: 42}, + HORSEA: {name: "SEADRA", val: 32}, + GOLDEEN: {name: "SEAKING", val: 33}, + SMOOCHUM: {name: "JYNX", val: 30}, + ELEKID: {name: "ELECTABUZZ", val: 30}, + MAGBY: {name: "MAGMAR", val: 30}, + MAGIKARP: {name: "GYARADOS", val: 20}, + OMANYTE: {name: "OMASTAR", val: 40}, + KABUTO: {name: "KABUTOPS", val: 40}, + DRATINI: {name: "DRAGONAIR", val: 30}, + DRAGONAIR: {name: "DRAGONITE", val: 55}, + CHIKORITA: {name: "BAYLEEF", val: 16}, + BAYLEEF: {name: "MEGANIUM", val: 32}, + CYNDAQUIL: {name: "QUILAVA", val: 14}, + QUILAVA: [{name: "HISUI_TYPHLOSION", val: 36}, {name: "TYPHLOSION", val: 36}], + TOTODILE: {name: "CROCONAW", val: 18}, + CROCONAW: {name: "FERALIGATR", val: 30}, + SENTRET: {name: "FURRET", val: 15}, + HOOTHOOT: {name: "NOCTOWL", val: 20}, + LEDYBA: {name: "LEDIAN", val: 18}, + SPINARAK: {name: "ARIADOS", val: 22}, + CHINCHOU: {name: "LANTURN", val: 27}, + NATU: {name: "XATU", val: 25}, + MAREEP: {name: "FLAAFFY", val: 15}, + FLAAFFY: {name: "AMPHAROS", val: 30}, + MARILL: {name: "AZUMARILL", val: 18}, + HOPPIP: {name: "SKIPLOOM", val: 18}, + SKIPLOOM: {name: "JUMPLUFF", val: 27}, + WOOPER: {name: "QUAGSIRE", val: 20}, + WYNAUT: {name: "WOBBUFFET", val: 15}, + PINECO: {name: "FORRETRESS", val: 31}, + SNUBBULL: {name: "GRANBULL", val: 23}, + TEDDIURSA: {name: "URSARING", val: 30}, + SLUGMA: {name: "MAGCARGO", val: 38}, + SWINUB: {name: "PILOSWINE", val: 33}, + REMORAID: {name: "OCTILLERY", val: 25}, + HOUNDOUR: {name: "HOUNDOOM", val: 24}, + PHANPY: {name: "DONPHAN", val: 25}, + LARVITAR: {name: "PUPITAR", val: 30}, + PUPITAR: {name: "TYRANITAR", val: 55}, + TREECKO: {name: "GROVYLE", val: 16}, + GROVYLE: {name: "SCEPTILE", val: 36}, + TORCHIC: {name: "COMBUSKEN", val: 16}, + COMBUSKEN: {name: "BLAZIKEN", val: 36}, + MUDKIP: {name: "MARSHTOMP", val: 16}, + MARSHTOMP: {name: "SWAMPERT", val: 36}, + POOCHYENA: {name: "MIGHTYENA", val: 18}, + ZIGZAGOON: {name: "LINOONE", val: 20}, + WURMPLE: [{name: "SILCOON", val: 7}, {name: "CASCOON", val: 7}], + SILCOON: {name: "BEAUTIFLY", val: 10}, + CASCOON: {name: "DUSTOX", val: 10}, + LOTAD: {name: "LOMBRE", val: 14}, + SEEDOT: {name: "NUZLEAF", val: 14}, + TAILLOW: {name: "SWELLOW", val: 22}, + WINGULL: {name: "PELIPPER", val: 25}, + RALTS: {name: "KIRLIA", val: 20}, + KIRLIA: [{name: "GARDEVOIR", val: 30}, {name: "GALLADE", val: 30}], + SURSKIT: {name: "MASQUERAIN", val: 22}, + SHROOMISH: {name: "BRELOOM", val: 23}, + SLAKOTH: {name: "VIGOROTH", val: 18}, + VIGOROTH: {name: "SLAKING", val: 36}, + NINCADA: [{name: "NINJASK", val: 20}, {name: "SHEDINJA", val: 20}], + WHISMUR: {name: "LOUDRED", val: 20}, + LOUDRED: {name: "EXPLOUD", val: 40}, + MAKUHITA: {name: "HARIYAMA", val: 24}, + ARON: {name: "LAIRON", val: 32}, + LAIRON: {name: "AGGRON", val: 42}, + MEDITITE: {name: "MEDICHAM", val: 37}, + ELECTRIKE: {name: "MANECTRIC", val: 26}, + GULPIN: {name: "SWALOT", val: 26}, + CARVANHA: {name: "SHARPEDO", val: 30}, + WAILMER: {name: "WAILORD", val: 40}, + NUMEL: {name: "CAMERUPT", val: 33}, + SPOINK: {name: "GRUMPIG", val: 32}, + TRAPINCH: {name: "VIBRAVA", val: 35}, + VIBRAVA: {name: "FLYGON", val: 45}, + CACNEA: {name: "CACTURNE", val: 32}, + SWABLU: {name: "ALTARIA", val: 35}, + BARBOACH: {name: "WHISCASH", val: 30}, + CORPHISH: {name: "CRAWDAUNT", val: 30}, + BALTOY: {name: "CLAYDOL", val: 36}, + LILEEP: {name: "CRADILY", val: 40}, + ANORITH: {name: "ARMALDO", val: 40}, + SHUPPET: {name: "BANETTE", val: 37}, + DUSKULL: {name: "DUSCLOPS", val: 37}, + SNORUNT: [{name: "GLALIE", val: 42}, {name: "FROSLASS", val: 42}], + SPHEAL: {name: "SEALEO", val: 32}, + SEALEO: {name: "WALREIN", val: 44}, + BAGON: {name: "SHELGON", val: 30}, + SHELGON: {name: "SALAMENCE", val: 50}, + BELDUM: {name: "METANG", val: 20}, + METANG: {name: "METAGROSS", val: 45}, + TURTWIG: {name: "GROTLE", val: 18}, + GROTLE: {name: "TORTERRA", val: 32}, + CHIMCHAR: {name: "MONFERNO", val: 14}, + MONFERNO: {name: "INFERNAPE", val: 36}, + PIPLUP: {name: "PRINPLUP", val: 16}, + PRINPLUP: {name: "EMPOLEON", val: 36}, + STARLY: {name: "STARAVIA", val: 14}, + STARAVIA: {name: "STARAPTOR", val: 34}, + BIDOOF: {name: "BIBAREL", val: 15}, + KRICKETOT: {name: "KRICKETUNE", val: 10}, + SHINX: {name: "LUXIO", val: 15}, + LUXIO: {name: "LUXRAY", val: 30}, + CRANIDOS: {name: "RAMPARDOS", val: 30}, + SHIELDON: {name: "BASTIODON", val: 30}, + BURMY: [{name: "MOTHIM", val: 20}, {name: "WORMADAM", val: 20}], + COMBEE: {name: "VESPIQUEN", val: 21}, + BUIZEL: {name: "FLOATZEL", val: 26}, + CHERUBI: {name: "CHERRIM", val: 25}, + SHELLOS: {name: "GASTRODON", val: 30}, + DRIFLOON: {name: "DRIFBLIM", val: 28}, + GLAMEOW: {name: "PURUGLY", val: 38}, + STUNKY: {name: "SKUNTANK", val: 34}, + BRONZOR: {name: "BRONZONG", val: 33}, + GIBLE: {name: "GABITE", val: 24}, + GABITE: {name: "GARCHOMP", val: 48}, + HIPPOPOTAS: {name: "HIPPOWDON", val: 34}, + SKORUPI: {name: "DRAPION", val: 40}, + CROAGUNK: {name: "TOXICROAK", val: 37}, + FINNEON: {name: "LUMINEON", val: 31}, + MANTYKE: {name: "MANTINE", val: 32}, + SNOVER: {name: "ABOMASNOW", val: 40}, + SNIVY: {name: "SERVINE", val: 17}, + SERVINE: {name: "SERPERIOR", val: 36}, + TEPIG: {name: "PIGNITE", val: 17}, + PIGNITE: {name: "EMBOAR", val: 36}, + OSHAWOTT: {name: "DEWOTT", val: 17}, + DEWOTT: [{name: "HISUI_SAMUROTT", val: 36}, {name: "SAMUROTT", val: 36}], + PATRAT: {name: "WATCHOG", val: 20}, + LILLIPUP: {name: "HERDIER", val: 16}, + HERDIER: {name: "STOUTLAND", val: 32}, + PURRLOIN: {name: "LIEPARD", val: 20}, + PIDOVE: {name: "TRANQUILL", val: 21}, + TRANQUILL: {name: "UNFEZANT", val: 32}, + BLITZLE: {name: "ZEBSTRIKA", val: 27}, + ROGGENROLA: {name: "BOLDORE", val: 25}, + DRILBUR: {name: "EXCADRILL", val: 31}, + TIMBURR: {name: "GURDURR", val: 25}, + TYMPOLE: {name: "PALPITOAD", val: 25}, + PALPITOAD: {name: "SEISMITOAD", val: 36}, + SEWADDLE: {name: "SWADLOON", val: 20}, + VENIPEDE: {name: "WHIRLIPEDE", val: 22}, + WHIRLIPEDE: {name: "SCOLIPEDE", val: 30}, + SANDILE: {name: "KROKOROK", val: 29}, + KROKOROK: {name: "KROOKODILE", val: 40}, + DARUMAKA: {name: "DARMANITAN", val: 35}, + DWEBBLE: {name: "CRUSTLE", val: 34}, + SCRAGGY: {name: "SCRAFTY", val: 39}, + YAMASK: {name: "COFAGRIGUS", val: 34}, + TIRTOUGA: {name: "CARRACOSTA", val: 37}, + ARCHEN: {name: "ARCHEOPS", val: 37}, + TRUBBISH: {name: "GARBODOR", val: 36}, + ZORUA: {name: "ZOROARK", val: 30}, + GOTHITA: {name: "GOTHORITA", val: 32}, + GOTHORITA: {name: "GOTHITELLE", val: 41}, + SOLOSIS: {name: "DUOSION", val: 32}, + DUOSION: {name: "REUNICLUS", val: 41}, + DUCKLETT: {name: "SWANNA", val: 35}, + VANILLITE: {name: "VANILLISH", val: 35}, + VANILLISH: {name: "VANILLUXE", val: 47}, + DEERLING: {name: "SAWSBUCK", val: 34}, + FOONGUS: {name: "AMOONGUSS", val: 39}, + FRILLISH: {name: "JELLICENT", val: 40}, + JOLTIK: {name: "GALVANTULA", val: 36}, + FERROSEED: {name: "FERROTHORN", val: 40}, + KLINK: {name: "KLANG", val: 38}, + KLANG: {name: "KLINKLANG", val: 49}, + TYNAMO: {name: "EELEKTRIK", val: 39}, + ELGYEM: {name: "BEHEEYEM", val: 42}, + LITWICK: {name: "LAMPENT", val: 41}, + AXEW: {name: "FRAXURE", val: 38}, + FRAXURE: {name: "HAXORUS", val: 48}, + CUBCHOO: {name: "BEARTIC", val: 37}, + MIENFOO: {name: "MIENSHAO", val: 50}, + GOLETT: {name: "GOLURK", val: 43}, + PAWNIARD: {name: "BISHARP", val: 52}, + BISHARP: {name: "KINGAMBIT", val: 64}, + RUFFLET: [{name: "HISUI_BRAVIARY", val: 54}, {name: "BRAVIARY", val: 54}], + VULLABY: {name: "MANDIBUZZ", val: 54}, + DEINO: {name: "ZWEILOUS", val: 50}, + ZWEILOUS: {name: "HYDREIGON", val: 64}, + LARVESTA: {name: "VOLCARONA", val: 59}, + CHESPIN: {name: "QUILLADIN", val: 16}, + QUILLADIN: {name: "CHESNAUGHT", val: 36}, + FENNEKIN: {name: "BRAIXEN", val: 16}, + BRAIXEN: {name: "DELPHOX", val: 36}, + FROAKIE: {name: "FROGADIER", val: 16}, + FROGADIER: {name: "GRENINJA", val: 36}, + BUNNELBY: {name: "DIGGERSBY", val: 20}, + FLETCHLING: {name: "FLETCHINDER", val: 17}, + FLETCHINDER: {name: "TALONFLAME", val: 35}, + SCATTERBUG: {name: "SPEWPA", val: 9}, + SPEWPA: {name: "VIVILLON", val: 12}, + LITLEO: {name: "PYROAR", val: 35}, + FLABEBE: {name: "FLOETTE", val: 19}, + SKIDDO: {name: "GOGOAT", val: 32}, + PANCHAM: {name: "PANGORO", val: 32}, + ESPURR: {name: "MEOWSTIC", val: 25}, + HONEDGE: {name: "DOUBLADE", val: 35}, + INKAY: {name: "MALAMAR", val: 30}, + BINACLE: {name: "BARBARACLE", val: 39}, + SKRELP: {name: "DRAGALGE", val: 48}, + CLAUNCHER: {name: "CLAWITZER", val: 37}, + TYRUNT: {name: "TYRANTRUM", val: 39}, + AMAURA: {name: "AURORUS", val: 39}, + GOOMY: [{name: "HISUI_SLIGGOO", val: 40}, {name: "SLIGGOO", val: 40}], + SLIGGOO: {name: "GOODRA", val: 50}, + BERGMITE: [{name: "HISUI_AVALUGG", val: 37}, {name: "AVALUGG", val: 37}], + NOIBAT: {name: "NOIVERN", val: 48}, + ROWLET: {name: "DARTRIX", val: 17}, + DARTRIX: [{name: "HISUI_DECIDUEYE", val: 36}, {name: "DECIDUEYE", val: 34}], + LITTEN: {name: "TORRACAT", val: 17}, + TORRACAT: {name: "INCINEROAR", val: 34}, + POPPLIO: {name: "BRIONNE", val: 17}, + BRIONNE: {name: "PRIMARINA", val: 34}, + PIKIPEK: {name: "TRUMBEAK", val: 14}, + TRUMBEAK: {name: "TOUCANNON", val: 28}, + YUNGOOS: {name: "GUMSHOOS", val: 20}, + GRUBBIN: {name: "CHARJABUG", val: 20}, + CUTIEFLY: {name: "RIBOMBEE", val: 25}, + MAREANIE: {name: "TOXAPEX", val: 38}, + MUDBRAY: {name: "MUDSDALE", val: 30}, + DEWPIDER: {name: "ARAQUANID", val: 22}, + FOMANTIS: {name: "LURANTIS", val: 34}, + MORELULL: {name: "SHIINOTIC", val: 24}, + SALANDIT: {name: "SALAZZLE", val: 33}, + STUFFUL: {name: "BEWEAR", val: 27}, + BOUNSWEET: {name: "STEENEE", val: 18}, + WIMPOD: {name: "GOLISOPOD", val: 30}, + SANDYGAST: {name: "PALOSSAND", val: 42}, + JANGMO_O: {name: "HAKAMO_O", val: 35}, + HAKAMO_O: {name: "KOMMO_O", val: 45}, + COSMOG: {name: "COSMOEM", val: 43}, + COSMOEM: [{name: "SOLGALEO", val: 53}, {name: "LUNALA", val: 53}], + MELTAN: {name: "MELMETAL", val: 48}, + ALOLA_RATTATA: {name: "ALOLA_RATICATE", val: 20}, + ALOLA_DIGLETT: {name: "ALOLA_DUGTRIO", val: 26}, + ALOLA_GEODUDE: {name: "ALOLA_GRAVELER", val: 25}, + ALOLA_GRIMER: {name: "ALOLA_MUK", val: 38}, + GROOKEY: {name: "THWACKEY", val: 16}, + THWACKEY: {name: "RILLABOOM", val: 35}, + SCORBUNNY: {name: "RABOOT", val: 16}, + RABOOT: {name: "CINDERACE", val: 35}, + SOBBLE: {name: "DRIZZILE", val: 16}, + DRIZZILE: {name: "INTELEON", val: 35}, + SKWOVET: {name: "GREEDENT", val: 24}, + ROOKIDEE: {name: "CORVISQUIRE", val: 18}, + CORVISQUIRE: {name: "CORVIKNIGHT", val: 38}, + BLIPBUG: {name: "DOTTLER", val: 10}, + DOTTLER: {name: "ORBEETLE", val: 30}, + NICKIT: {name: "THIEVUL", val: 18}, + GOSSIFLEUR: {name: "ELDEGOSS", val: 20}, + WOOLOO: {name: "DUBWOOL", val: 24}, + CHEWTLE: {name: "DREDNAW", val: 22}, + YAMPER: {name: "BOLTUND", val: 25}, + ROLYCOLY: {name: "CARKOL", val: 18}, + CARKOL: {name: "COALOSSAL", val: 34}, + SILICOBRA: {name: "SANDACONDA", val: 36}, + ARROKUDA: {name: "BARRASKEWDA", val: 26}, + TOXEL: {name: "TOXTRICITY", val: 30}, + SIZZLIPEDE: {name: "CENTISKORCH", val: 28}, + HATENNA: {name: "HATTREM", val: 32}, + HATTREM: {name: "HATTERENE", val: 42}, + IMPIDIMP: {name: "MORGREM", val: 32}, + MORGREM: {name: "GRIMMSNARL", val: 42}, + CUFANT: {name: "COPPERAJAH", val: 34}, + DREEPY: {name: "DRAKLOAK", val: 50}, + DRAKLOAK: {name: "DRAGAPULT", val: 60}, + GALAR_MEOWTH: {name: "PERRSERKER", val: 28}, + GALAR_PONYTA: {name: "GALAR_RAPIDASH", val: 40}, + GALAR_FARFETCHD: {name: "SIRFETCHD", val: 30}, + GALAR_SLOWPOKE: [{name: "GALAR_SLOWBRO", val: 1}, {name: "GALAR_SLOWKING", val: 1}], + GALAR_MR_MIME: {name: "MR_RIME", val: 42}, + GALAR_CORSOLA: {name: "CURSOLA", val: 38}, + GALAR_ZIGZAGOON: {name: "GALAR_LINOONE", val: 20}, + GALAR_LINOONE: {name: "OBSTAGOON", val: 35}, + GALAR_YAMASK: {name: "RUNERIGUS", val: 34}, + HISUI_ZORUA: {name: "HISUI_ZOROARK", val: 30}, + HISUI_SLIGGOO: {name: "HISUI_GOODRA", val: 50}, + SPRIGATITO: {name: "FLORAGATO", val: 16}, + FLORAGATO: {name: "MEOWSCARADA", val: 36}, + FUECOCO: {name: "CROCALOR", val: 16}, + CROCALOR: {name: "SKELEDIRGE", val: 36}, + QUAXLY: {name: "QUAXWELL", val: 16}, + QUAXWELL: {name: "QUAQUAVAL", val: 36}, + LECHONK: {name: "OINKOLOGNE", val: 18}, + TAROUNTULA: {name: "SPIDOPS", val: 15}, + NYMBLE: {name: "LOKIX", val: 24}, + PAWMI: {name: "PAWMO", val: 18}, + PAWMO: {name: "PAWMOT", val: 32}, + TANDEMAUS: {name: "MAUSHOLD", val: 25}, + FIDOUGH: {name: "DACHSBUN", val: 26}, + SMOLIV: {name: "DOLLIV", val: 25}, + DOLLIV: {name: "ARBOLIVA", val: 35}, + NACLI: {name: "NACLSTACK", val: 24}, + NACLSTACK: {name: "GARGANACL", val: 38}, + WATTREL: {name: "KILOWATTREL", val: 25}, + MASCHIFF: {name: "MABOSSTIFF", val: 30}, + SHROODLE: {name: "GRAFAIAI", val: 28}, + BRAMBLIN: {name: "BRAMBLEGHAST", val: 30}, + TOEDSCOOL: {name: "TOEDSCRUEL", val: 30}, + RELLOR: {name: "RABSCA", val: 29}, + FLITTLE: {name: "ESPATHRA", val: 35}, + TINKATINK: {name: "TINKATUFF", val: 24}, + TINKATUFF: {name: "TINKATON", val: 38}, + WIGLETT: {name: "WUGTRIO", val: 26}, + FINIZEN: {name: "PALAFIN", val: 38}, + VAROOM: {name: "REVAVROOM", val: 40}, + GLIMMET: {name: "GLIMMORA", val: 35}, + GREAVARD: {name: "HOUNDSTONE", val: 30}, + FRIGIBAX: {name: "ARCTIBAX", val: 35}, + ARCTIBAX: {name: "BAXCALIBUR", val: 54}, + PALDEA_WOOPER: {name: "CLODSIRE", val: 20}, + PIKACHU: [{name: "ALOLA_RAICHU", val: 1}, {name: "RAICHU", val: 1}], + NIDORINA: {name: "NIDOQUEEN", val: 1}, + NIDORINO: {name: "NIDOKING", val: 1}, + CLEFAIRY: {name: "CLEFABLE", val: 1}, + VULPIX: {name: "NINETALES", val: 1}, + JIGGLYPUFF: {name: "WIGGLYTUFF", val: 1}, + GLOOM: [{name: "VILEPLUME", val: 1}, {name: "BELLOSSOM", val: 1}], + GROWLITHE: {name: "ARCANINE", val: 1}, + POLIWHIRL: [{name: "POLIWRATH", val: 1}, {name: "POLITOED", val: 1}], + WEEPINBELL: {name: "VICTREEBEL", val: 1}, + MAGNETON: {name: "MAGNEZONE", val: 1}, + SHELLDER: {name: "CLOYSTER", val: 1}, + EXEGGCUTE: [{name: "ALOLA_EXEGGUTOR", val: 1}, {name: "EXEGGUTOR", val: 1}], + TANGELA: {name: "TANGROWTH", val: 34}, + LICKITUNG: {name: "LICKILICKY", val: 32}, + STARYU: {name: "STARMIE", val: 1}, + EEVEE: [{name: "SYLVEON", val: 1},{name: "ESPEON", val: 1},{name: "UMBREON", val: 1}, {name: "VAPOREON", val: 1}, {name: "JOLTEON", val: 1}, {name: "FLAREON", val: 1}, {name: "LEAFEON", val: 1}, {name: "GLACEON", val: 1} ], + TOGETIC: {name: "TOGEKISS", val: 1}, + AIPOM: {name: "AMBIPOM", val: 32}, + SUNKERN: {name: "SUNFLORA", val: 1}, + YANMA: {name: "YANMEGA", val: 33}, + MURKROW: {name: "HONCHKROW", val: 1}, + MISDREAVUS: {name: "MISMAGIUS", val: 1}, + GIRAFARIG: {name: "FARIGIRAF", val: 32}, + DUNSPARCE: {name: "DUDUNSPARCE", val: 32}, + GLIGAR: {name: "GLISCOR", val: 1}, + SNEASEL: {name: "WEAVILE", val: 1}, + URSARING: {name: "URSALUNA", val: 1}, + PILOSWINE: {name: "MAMOSWINE", val: 1}, + STANTLER: {name: "WYRDEER", val: 25}, + LOMBRE: {name: "LUDICOLO", val: 1}, + NUZLEAF: {name: "SHIFTRY", val: 1}, + NOSEPASS: {name: "PROBOPASS", val: 1}, + SKITTY: {name: "DELCATTY", val: 1}, + ROSELIA: {name: "ROSERADE", val: 1}, + BONSLY: {name: "SUDOWOODO", val: 1}, + MIME_JR: [{name: "GALAR_MR_MIME", val: 1},{name: "MR_MIME", val: 1}], + PANSAGE: {name: "SIMISAGE", val: 1}, + PANSEAR: {name: "SIMISEAR", val: 1}, + PANPOUR: {name: "SIMIPOUR", val: 1}, + MUNNA: {name: "MUSHARNA", val: 1}, + COTTONEE: {name: "WHIMSICOTT", val: 1}, + PETILIL: [{name: "HISUI_LILLIGANT", val: 1}, {name: "LILLIGANT", val: 1}], + BASCULIN: {name: "BASCULEGION", val: 40}, + MINCCINO: {name: "CINCCINO", val: 1}, + EELEKTRIK: {name: "EELEKTROSS", val: 1}, + LAMPENT: {name: "CHANDELURE", val: 1}, + FLOETTE: {name: "FLORGES", val: 1}, + DOUBLADE: {name: "AEGISLASH", val: 1}, + HELIOPTILE: {name: "HELIOLISK", val: 1}, + CHARJABUG: {name: "VIKAVOLT", val: 1}, + CRABRAWLER: {name: "CRABOMINABLE", val: 1}, + ROCKRUFF: {name: "LYCANROC", val: 25}, + STEENEE: {name: "TSAREENA", val: 28}, + POIPOLE: {name: "NAGANADEL", val: 1}, + ALOLA_SANDSHREW: {name: "ALOLA_SANDSLASH", val: 1}, + ALOLA_VULPIX: {name: "ALOLA_NINETALES", val: 1}, + APPLIN: [{name: "DIPPLIN", val: 1},{name: "FLAPPLE", val: 1}, {name: "APPLETUN", val: 1}], + CLOBBOPUS: {name: "GRAPPLOCT", val: 35}, + SINISTEA: {name: "POLTEAGEIST", val: 1}, + MILCERY: {name: "ALCREMIE", val: 1}, + DURALUDON: {name: "ARCHALUDON", val: 1}, + KUBFU: {name: "URSHIFU", val: 1}, + GALAR_DARUMAKA: {name: "GALAR_DARMANITAN", val: 1}, + HISUI_GROWLITHE: {name: "HISUI_ARCANINE", val: 1}, + HISUI_VOLTORB: {name: "HISUI_ELECTRODE", val: 1}, + HISUI_QWILFISH: {name: "OVERQWIL", val: 28}, + HISUI_SNEASEL: {name: "SNEASLER", val: 1}, + CHARCADET: [{name: "ARMAROUGE", val: 1}, {name: "CERULEDGE", val: 1}], + TADBULB: {name: "BELLIBOLT", val: 1}, + CAPSAKID: {name: "SCOVILLAIN", val: 1}, + CETODDLE: {name: "CETITAN", val: 1}, + POLTCHAGEIST: {name: "SINISTCHA", val: 1}, + DIPPLIN: {name: "HYDRAPPLE", val: 1}, + KADABRA: {name: "ALAKAZAM", val: 1}, + MACHOKE: {name: "MACHAMP", val: 1}, + GRAVELER: {name: "GOLEM", val: 1}, + HAUNTER: {name: "GENGAR", val: 1}, + ONIX: {name: "STEELIX", val: 1}, + RHYDON: {name: "RHYPERIOR", val: 1}, + SEADRA: {name: "KINGDRA", val: 1}, + SCYTHER: [{name: "SCIZOR", val: 1}, {name: "KLEAVOR", val: 1}], + ELECTABUZZ: {name: "ELECTIVIRE", val: 1}, + MAGMAR: {name: "MAGMORTAR", val: 1}, + PORYGON: {name: "PORYGON2", val: 1}, + PORYGON2: {name: "PORYGON_Z", val: 1}, + FEEBAS: {name: "MILOTIC", val: 1}, + DUSCLOPS: {name: "DUSKNOIR", val: 1}, + CLAMPERL: [{name: "HUNTAIL", val: 1}, {name: "GOREBYSS", val: 1}], + BOLDORE: {name: "GIGALITH", val: 1}, + GURDURR: {name: "CONKELDURR", val: 1}, + KARRABLAST: {name: "ESCAVALIER", val: 1}, + SHELMET: {name: "ACCELGOR", val: 1}, + SPRITZEE: {name: "AROMATISSE", val: 1}, + SWIRLIX: {name: "SLURPUFF", val: 1}, + PHANTUMP: {name: "TREVENANT", val: 1}, + PUMPKABOO: {name: "GOURGEIST", val: 1}, + ALOLA_GRAVELER: {name: "ALOLA_GOLEM", val: 1}, + PRIMEAPE: {name: "ANNIHILAPE", val: 35}, + GOLBAT: {name: "CROBAT", val: 1}, + CHANSEY: {name: "BLISSEY", val: 1}, + PICHU: {name: "PIKACHU", val: 1}, + CLEFFA: {name: "CLEFAIRY", val: 1}, + IGGLYBUFF: {name: "JIGGLYPUFF", val: 1}, + TOGEPI: {name: "TOGETIC", val: 1}, + AZURILL: {name: "MARILL", val: 1}, + BUDEW: {name: "ROSELIA", val: 1}, + BUNEARY: {name: "LOPUNNY", val: 1}, + CHINGLING: {name: "CHIMECHO", val: 1}, + HAPPINY: {name: "CHANSEY", val: 1}, + MUNCHLAX: {name: "SNORLAX", val: 1}, + RIOLU: {name: "LUCARIO", val: 1}, + WOOBAT: {name: "SWOOBAT", val: 1}, + SWADLOON: {name: "LEAVANNY", val: 1}, + TYPE_NULL: {name: "SILVALLY", val: 1}, + ALOLA_MEOWTH: {name: "ALOLA_PERSIAN", val: 1}, + SNOM: {name: "FROSMOTH", val: 1}, + GIMMIGHOUL: {name: "GHOLDENGO", val: 1} +}; + +// export default EvolutionMap; \ No newline at end of file diff --git a/content/maps/Pokemon_To_Id.js b/content/maps/Pokemon_To_Id.js new file mode 100644 index 0000000..0923049 --- /dev/null +++ b/content/maps/Pokemon_To_Id.js @@ -0,0 +1,1086 @@ +window["__Species"] = { + BULBASAUR: 1, + IVYSAUR: 2, + VENUSAUR: 3, + CHARMANDER: 4, + CHARMELEON: 5, + CHARIZARD: 6, + SQUIRTLE: 7, + WARTORTLE: 8, + BLASTOISE: 9, + CATERPIE: 10, + METAPOD: 11, + BUTTERFREE: 12, + WEEDLE: 13, + KAKUNA: 14, + BEEDRILL: 15, + PIDGEY: 16, + PIDGEOTTO: 17, + PIDGEOT: 18, + RATTATA: 19, + RATICATE: 20, + SPEAROW: 21, + FEAROW: 22, + EKANS: 23, + ARBOK: 24, + PIKACHU: 25, + RAICHU: 26, + SANDSHREW: 27, + SANDSLASH: 28, + NIDORAN_F: 29, + NIDORINA: 30, + NIDOQUEEN: 31, + NIDORAN_M: 32, + NIDORINO: 33, + NIDOKING: 34, + CLEFAIRY: 35, + CLEFABLE: 36, + VULPIX: 37, + NINETALES: 38, + JIGGLYPUFF: 39, + WIGGLYTUFF: 40, + ZUBAT: 41, + GOLBAT: 42, + ODDISH: 43, + GLOOM: 44, + VILEPLUME: 45, + PARAS: 46, + PARASECT: 47, + VENONAT: 48, + VENOMOTH: 49, + DIGLETT: 50, + DUGTRIO: 51, + MEOWTH: 52, + PERSIAN: 53, + PSYDUCK: 54, + GOLDUCK: 55, + MANKEY: 56, + PRIMEAPE: 57, + GROWLITHE: 58, + ARCANINE: 59, + POLIWAG: 60, + POLIWHIRL: 61, + POLIWRATH: 62, + ABRA: 63, + KADABRA: 64, + ALAKAZAM: 65, + MACHOP: 66, + MACHOKE: 67, + MACHAMP: 68, + BELLSPROUT: 69, + WEEPINBELL: 70, + VICTREEBEL: 71, + TENTACOOL: 72, + TENTACRUEL: 73, + GEODUDE: 74, + GRAVELER: 75, + GOLEM: 76, + PONYTA: 77, + RAPIDASH: 78, + SLOWPOKE: 79, + SLOWBRO: 80, + MAGNEMITE: 81, + MAGNETON: 82, + FARFETCHD: 83, + DODUO: 84, + DODRIO: 85, + SEEL: 86, + DEWGONG: 87, + GRIMER: 88, + MUK: 89, + SHELLDER: 90, + CLOYSTER: 91, + GASTLY: 92, + HAUNTER: 93, + GENGAR: 94, + ONIX: 95, + DROWZEE: 96, + HYPNO: 97, + KRABBY: 98, + KINGLER: 99, + VOLTORB: 100, + ELECTRODE: 101, + EXEGGCUTE: 102, + EXEGGUTOR: 103, + CUBONE: 104, + MAROWAK: 105, + HITMONLEE: 106, + HITMONCHAN: 107, + LICKITUNG: 108, + KOFFING: 109, + WEEZING: 110, + RHYHORN: 111, + RHYDON: 112, + CHANSEY: 113, + TANGELA: 114, + KANGASKHAN: 115, + HORSEA: 116, + SEADRA: 117, + GOLDEEN: 118, + SEAKING: 119, + STARYU: 120, + STARMIE: 121, + MR_MIME: 122, + SCYTHER: 123, + JYNX: 124, + ELECTABUZZ: 125, + MAGMAR: 126, + PINSIR: 127, + TAUROS: 128, + MAGIKARP: 129, + GYARADOS: 130, + LAPRAS: 131, + DITTO: 132, + EEVEE: 133, + VAPOREON: 134, + JOLTEON: 135, + FLAREON: 136, + PORYGON: 137, + OMANYTE: 138, + OMASTAR: 139, + KABUTO: 140, + KABUTOPS: 141, + AERODACTYL: 142, + SNORLAX: 143, + ARTICUNO: 144, + ZAPDOS: 145, + MOLTRES: 146, + DRATINI: 147, + DRAGONAIR: 148, + DRAGONITE: 149, + MEWTWO: 150, + MEW: 151, + CHIKORITA: 152, + BAYLEEF: 153, + MEGANIUM: 154, + CYNDAQUIL: 155, + QUILAVA: 156, + TYPHLOSION: 157, + TOTODILE: 158, + CROCONAW: 159, + FERALIGATR: 160, + SENTRET: 161, + FURRET: 162, + HOOTHOOT: 163, + NOCTOWL: 164, + LEDYBA: 165, + LEDIAN: 166, + SPINARAK: 167, + ARIADOS: 168, + CROBAT: 169, + CHINCHOU: 170, + LANTURN: 171, + PICHU: 172, + CLEFFA: 173, + IGGLYBUFF: 174, + TOGEPI: 175, + TOGETIC: 176, + NATU: 177, + XATU: 178, + MAREEP: 179, + FLAAFFY: 180, + AMPHAROS: 181, + BELLOSSOM: 182, + MARILL: 183, + AZUMARILL: 184, + SUDOWOODO: 185, + POLITOED: 186, + HOPPIP: 187, + SKIPLOOM: 188, + JUMPLUFF: 189, + AIPOM: 190, + SUNKERN: 191, + SUNFLORA: 192, + YANMA: 193, + WOOPER: 194, + QUAGSIRE: 195, + ESPEON: 196, + UMBREON: 197, + MURKROW: 198, + SLOWKING: 199, + MISDREAVUS: 200, + UNOWN: 201, + WOBBUFFET: 202, + GIRAFARIG: 203, + PINECO: 204, + FORRETRESS: 205, + DUNSPARCE: 206, + GLIGAR: 207, + STEELIX: 208, + SNUBBULL: 209, + GRANBULL: 210, + QWILFISH: 211, + SCIZOR: 212, + SHUCKLE: 213, + HERACROSS: 214, + SNEASEL: 215, + TEDDIURSA: 216, + URSARING: 217, + SLUGMA: 218, + MAGCARGO: 219, + SWINUB: 220, + PILOSWINE: 221, + CORSOLA: 222, + REMORAID: 223, + OCTILLERY: 224, + DELIBIRD: 225, + MANTINE: 226, + SKARMORY: 227, + HOUNDOUR: 228, + HOUNDOOM: 229, + KINGDRA: 230, + PHANPY: 231, + DONPHAN: 232, + PORYGON2: 233, + STANTLER: 234, + SMEARGLE: 235, + TYROGUE: 236, + HITMONTOP: 237, + SMOOCHUM: 238, + ELEKID: 239, + MAGBY: 240, + MILTANK: 241, + BLISSEY: 242, + RAIKOU: 243, + ENTEI: 244, + SUICUNE: 245, + LARVITAR: 246, + PUPITAR: 247, + TYRANITAR: 248, + LUGIA: 249, + HO_OH: 250, + CELEBI: 251, + TREECKO: 252, + GROVYLE: 253, + SCEPTILE: 254, + TORCHIC: 255, + COMBUSKEN: 256, + BLAZIKEN: 257, + MUDKIP: 258, + MARSHTOMP: 259, + SWAMPERT: 260, + POOCHYENA: 261, + MIGHTYENA: 262, + ZIGZAGOON: 263, + LINOONE: 264, + WURMPLE: 265, + SILCOON: 266, + BEAUTIFLY: 267, + CASCOON: 268, + DUSTOX: 269, + LOTAD: 270, + LOMBRE: 271, + LUDICOLO: 272, + SEEDOT: 273, + NUZLEAF: 274, + SHIFTRY: 275, + TAILLOW: 276, + SWELLOW: 277, + WINGULL: 278, + PELIPPER: 279, + RALTS: 280, + KIRLIA: 281, + GARDEVOIR: 282, + SURSKIT: 283, + MASQUERAIN: 284, + SHROOMISH: 285, + BRELOOM: 286, + SLAKOTH: 287, + VIGOROTH: 288, + SLAKING: 289, + NINCADA: 290, + NINJASK: 291, + SHEDINJA: 292, + WHISMUR: 293, + LOUDRED: 294, + EXPLOUD: 295, + MAKUHITA: 296, + HARIYAMA: 297, + AZURILL: 298, + NOSEPASS: 299, + SKITTY: 300, + DELCATTY: 301, + SABLEYE: 302, + MAWILE: 303, + ARON: 304, + LAIRON: 305, + AGGRON: 306, + MEDITITE: 307, + MEDICHAM: 308, + ELECTRIKE: 309, + MANECTRIC: 310, + PLUSLE: 311, + MINUN: 312, + VOLBEAT: 313, + ILLUMISE: 314, + ROSELIA: 315, + GULPIN: 316, + SWALOT: 317, + CARVANHA: 318, + SHARPEDO: 319, + WAILMER: 320, + WAILORD: 321, + NUMEL: 322, + CAMERUPT: 323, + TORKOAL: 324, + SPOINK: 325, + GRUMPIG: 326, + SPINDA: 327, + TRAPINCH: 328, + VIBRAVA: 329, + FLYGON: 330, + CACNEA: 331, + CACTURNE: 332, + SWABLU: 333, + ALTARIA: 334, + ZANGOOSE: 335, + SEVIPER: 336, + LUNATONE: 337, + SOLROCK: 338, + BARBOACH: 339, + WHISCASH: 340, + CORPHISH: 341, + CRAWDAUNT: 342, + BALTOY: 343, + CLAYDOL: 344, + LILEEP: 345, + CRADILY: 346, + ANORITH: 347, + ARMALDO: 348, + FEEBAS: 349, + MILOTIC: 350, + CASTFORM: 351, + KECLEON: 352, + SHUPPET: 353, + BANETTE: 354, + DUSKULL: 355, + DUSCLOPS: 356, + TROPIUS: 357, + CHIMECHO: 358, + ABSOL: 359, + WYNAUT: 360, + SNORUNT: 361, + GLALIE: 362, + SPHEAL: 363, + SEALEO: 364, + WALREIN: 365, + CLAMPERL: 366, + HUNTAIL: 367, + GOREBYSS: 368, + RELICANTH: 369, + LUVDISC: 370, + BAGON: 371, + SHELGON: 372, + SALAMENCE: 373, + BELDUM: 374, + METANG: 375, + METAGROSS: 376, + REGIROCK: 377, + REGICE: 378, + REGISTEEL: 379, + LATIAS: 380, + LATIOS: 381, + KYOGRE: 382, + GROUDON: 383, + RAYQUAZA: 384, + JIRACHI: 385, + DEOXYS: 386, + TURTWIG: 387, + GROTLE: 388, + TORTERRA: 389, + CHIMCHAR: 390, + MONFERNO: 391, + INFERNAPE: 392, + PIPLUP: 393, + PRINPLUP: 394, + EMPOLEON: 395, + STARLY: 396, + STARAVIA: 397, + STARAPTOR: 398, + BIDOOF: 399, + BIBAREL: 400, + KRICKETOT: 401, + KRICKETUNE: 402, + SHINX: 403, + LUXIO: 404, + LUXRAY: 405, + BUDEW: 406, + ROSERADE: 407, + CRANIDOS: 408, + RAMPARDOS: 409, + SHIELDON: 410, + BASTIODON: 411, + BURMY: 412, + WORMADAM: 413, + MOTHIM: 414, + COMBEE: 415, + VESPIQUEN: 416, + PACHIRISU: 417, + BUIZEL: 418, + FLOATZEL: 419, + CHERUBI: 420, + CHERRIM: 421, + SHELLOS: 422, + GASTRODON: 423, + AMBIPOM: 424, + DRIFLOON: 425, + DRIFBLIM: 426, + BUNEARY: 427, + LOPUNNY: 428, + MISMAGIUS: 429, + HONCHKROW: 430, + GLAMEOW: 431, + PURUGLY: 432, + CHINGLING: 433, + STUNKY: 434, + SKUNTANK: 435, + BRONZOR: 436, + BRONZONG: 437, + BONSLY: 438, + MIME_JR: 439, + HAPPINY: 440, + CHATOT: 441, + SPIRITOMB: 442, + GIBLE: 443, + GABITE: 444, + GARCHOMP: 445, + MUNCHLAX: 446, + RIOLU: 447, + LUCARIO: 448, + HIPPOPOTAS: 449, + HIPPOWDON: 450, + SKORUPI: 451, + DRAPION: 452, + CROAGUNK: 453, + TOXICROAK: 454, + CARNIVINE: 455, + FINNEON: 456, + LUMINEON: 457, + MANTYKE: 458, + SNOVER: 459, + ABOMASNOW: 460, + WEAVILE: 461, + MAGNEZONE: 462, + LICKILICKY: 463, + RHYPERIOR: 464, + TANGROWTH: 465, + ELECTIVIRE: 466, + MAGMORTAR: 467, + TOGEKISS: 468, + YANMEGA: 469, + LEAFEON: 470, + GLACEON: 471, + GLISCOR: 472, + MAMOSWINE: 473, + PORYGON_Z: 474, + GALLADE: 475, + PROBOPASS: 476, + DUSKNOIR: 477, + FROSLASS: 478, + ROTOM: 479, + UXIE: 480, + MESPRIT: 481, + AZELF: 482, + DIALGA: 483, + PALKIA: 484, + HEATRAN: 485, + REGIGIGAS: 486, + GIRATINA: 487, + CRESSELIA: 488, + PHIONE: 489, + MANAPHY: 490, + DARKRAI: 491, + SHAYMIN: 492, + ARCEUS: 493, + VICTINI: 494, + SNIVY: 495, + SERVINE: 496, + SERPERIOR: 497, + TEPIG: 498, + PIGNITE: 499, + EMBOAR: 500, + OSHAWOTT: 501, + DEWOTT: 502, + SAMUROTT: 503, + PATRAT: 504, + WATCHOG: 505, + LILLIPUP: 506, + HERDIER: 507, + STOUTLAND: 508, + PURRLOIN: 509, + LIEPARD: 510, + PANSAGE: 511, + SIMISAGE: 512, + PANSEAR: 513, + SIMISEAR: 514, + PANPOUR: 515, + SIMIPOUR: 516, + MUNNA: 517, + MUSHARNA: 518, + PIDOVE: 519, + TRANQUILL: 520, + UNFEZANT: 521, + BLITZLE: 522, + ZEBSTRIKA: 523, + ROGGENROLA: 524, + BOLDORE: 525, + GIGALITH: 526, + WOOBAT: 527, + SWOOBAT: 528, + DRILBUR: 529, + EXCADRILL: 530, + AUDINO: 531, + TIMBURR: 532, + GURDURR: 533, + CONKELDURR: 534, + TYMPOLE: 535, + PALPITOAD: 536, + SEISMITOAD: 537, + THROH: 538, + SAWK: 539, + SEWADDLE: 540, + SWADLOON: 541, + LEAVANNY: 542, + VENIPEDE: 543, + WHIRLIPEDE: 544, + SCOLIPEDE: 545, + COTTONEE: 546, + WHIMSICOTT: 547, + PETILIL: 548, + LILLIGANT: 549, + BASCULIN: 550, + SANDILE: 551, + KROKOROK: 552, + KROOKODILE: 553, + DARUMAKA: 554, + DARMANITAN: 555, + MARACTUS: 556, + DWEBBLE: 557, + CRUSTLE: 558, + SCRAGGY: 559, + SCRAFTY: 560, + SIGILYPH: 561, + YAMASK: 562, + COFAGRIGUS: 563, + TIRTOUGA: 564, + CARRACOSTA: 565, + ARCHEN: 566, + ARCHEOPS: 567, + TRUBBISH: 568, + GARBODOR: 569, + ZORUA: 570, + ZOROARK: 571, + MINCCINO: 572, + CINCCINO: 573, + GOTHITA: 574, + GOTHORITA: 575, + GOTHITELLE: 576, + SOLOSIS: 577, + DUOSION: 578, + REUNICLUS: 579, + DUCKLETT: 580, + SWANNA: 581, + VANILLITE: 582, + VANILLISH: 583, + VANILLUXE: 584, + DEERLING: 585, + SAWSBUCK: 586, + EMOLGA: 587, + KARRABLAST: 588, + ESCAVALIER: 589, + FOONGUS: 590, + AMOONGUSS: 591, + FRILLISH: 592, + JELLICENT: 593, + ALOMOMOLA: 594, + JOLTIK: 595, + GALVANTULA: 596, + FERROSEED: 597, + FERROTHORN: 598, + KLINK: 599, + KLANG: 600, + KLINKLANG: 601, + TYNAMO: 602, + EELEKTRIK: 603, + EELEKTROSS: 604, + ELGYEM: 605, + BEHEEYEM: 606, + LITWICK: 607, + LAMPENT: 608, + CHANDELURE: 609, + AXEW: 610, + FRAXURE: 611, + HAXORUS: 612, + CUBCHOO: 613, + BEARTIC: 614, + CRYOGONAL: 615, + SHELMET: 616, + ACCELGOR: 617, + STUNFISK: 618, + MIENFOO: 619, + MIENSHAO: 620, + DRUDDIGON: 621, + GOLETT: 622, + GOLURK: 623, + PAWNIARD: 624, + BISHARP: 625, + BOUFFALANT: 626, + RUFFLET: 627, + BRAVIARY: 628, + VULLABY: 629, + MANDIBUZZ: 630, + HEATMOR: 631, + DURANT: 632, + DEINO: 633, + ZWEILOUS: 634, + HYDREIGON: 635, + LARVESTA: 636, + VOLCARONA: 637, + COBALION: 638, + TERRAKION: 639, + VIRIZION: 640, + TORNADUS: 641, + THUNDURUS: 642, + RESHIRAM: 643, + ZEKROM: 644, + LANDORUS: 645, + KYUREM: 646, + KELDEO: 647, + MELOETTA: 648, + GENESECT: 649, + CHESPIN: 650, + QUILLADIN: 651, + CHESNAUGHT: 652, + FENNEKIN: 653, + BRAIXEN: 654, + DELPHOX: 655, + FROAKIE: 656, + FROGADIER: 657, + GRENINJA: 658, + BUNNELBY: 659, + DIGGERSBY: 660, + FLETCHLING: 661, + FLETCHINDER: 662, + TALONFLAME: 663, + SCATTERBUG: 664, + SPEWPA: 665, + VIVILLON: 666, + LITLEO: 667, + PYROAR: 668, + FLABEBE: 669, + FLOETTE: 670, + FLORGES: 671, + SKIDDO: 672, + GOGOAT: 673, + PANCHAM: 674, + PANGORO: 675, + FURFROU: 676, + ESPURR: 677, + MEOWSTIC: 678, + HONEDGE: 679, + DOUBLADE: 680, + AEGISLASH: 681, + SPRITZEE: 682, + AROMATISSE: 683, + SWIRLIX: 684, + SLURPUFF: 685, + INKAY: 686, + MALAMAR: 687, + BINACLE: 688, + BARBARACLE: 689, + SKRELP: 690, + DRAGALGE: 691, + CLAUNCHER: 692, + CLAWITZER: 693, + HELIOPTILE: 694, + HELIOLISK: 695, + TYRUNT: 696, + TYRANTRUM: 697, + AMAURA: 698, + AURORUS: 699, + SYLVEON: 700, + HAWLUCHA: 701, + DEDENNE: 702, + CARBINK: 703, + GOOMY: 704, + SLIGGOO: 705, + GOODRA: 706, + KLEFKI: 707, + PHANTUMP: 708, + TREVENANT: 709, + PUMPKABOO: 710, + GOURGEIST: 711, + BERGMITE: 712, + AVALUGG: 713, + NOIBAT: 714, + NOIVERN: 715, + XERNEAS: 716, + YVELTAL: 717, + ZYGARDE: 718, + DIANCIE: 719, + HOOPA: 720, + VOLCANION: 721, + ROWLET: 722, + DARTRIX: 723, + DECIDUEYE: 724, + LITTEN: 725, + TORRACAT: 726, + INCINEROAR: 727, + POPPLIO: 728, + BRIONNE: 729, + PRIMARINA: 730, + PIKIPEK: 731, + TRUMBEAK: 732, + TOUCANNON: 733, + YUNGOOS: 734, + GUMSHOOS: 735, + GRUBBIN: 736, + CHARJABUG: 737, + VIKAVOLT: 738, + CRABRAWLER: 739, + CRABOMINABLE: 740, + ORICORIO: 741, + CUTIEFLY: 742, + RIBOMBEE: 743, + ROCKRUFF: 744, + LYCANROC: 745, + WISHIWASHI: 746, + MAREANIE: 747, + TOXAPEX: 748, + MUDBRAY: 749, + MUDSDALE: 750, + DEWPIDER: 751, + ARAQUANID: 752, + FOMANTIS: 753, + LURANTIS: 754, + MORELULL: 755, + SHIINOTIC: 756, + SALANDIT: 757, + SALAZZLE: 758, + STUFFUL: 759, + BEWEAR: 760, + BOUNSWEET: 761, + STEENEE: 762, + TSAREENA: 763, + COMFEY: 764, + ORANGURU: 765, + PASSIMIAN: 766, + WIMPOD: 767, + GOLISOPOD: 768, + SANDYGAST: 769, + PALOSSAND: 770, + PYUKUMUKU: 771, + TYPE_NULL: 772, + SILVALLY: 773, + MINIOR: 774, + KOMALA: 775, + TURTONATOR: 776, + TOGEDEMARU: 777, + MIMIKYU: 778, + BRUXISH: 779, + DRAMPA: 780, + DHELMISE: 781, + JANGMO_O: 782, + HAKAMO_O: 783, + KOMMO_O: 784, + TAPU_KOKO: 785, + TAPU_LELE: 786, + TAPU_BULU: 787, + TAPU_FINI: 788, + COSMOG: 789, + COSMOEM: 790, + SOLGALEO: 791, + LUNALA: 792, + NIHILEGO: 793, + BUZZWOLE: 794, + PHEROMOSA: 795, + XURKITREE: 796, + CELESTEELA: 797, + KARTANA: 798, + GUZZLORD: 799, + NECROZMA: 800, + MAGEARNA: 801, + MARSHADOW: 802, + POIPOLE: 803, + NAGANADEL: 804, + STAKATAKA: 805, + BLACEPHALON: 806, + ZERAORA: 807, + MELTAN: 808, + MELMETAL: 809, + GROOKEY: 810, + THWACKEY: 811, + RILLABOOM: 812, + SCORBUNNY: 813, + RABOOT: 814, + CINDERACE: 815, + SOBBLE: 816, + DRIZZILE: 817, + INTELEON: 818, + SKWOVET: 819, + GREEDENT: 820, + ROOKIDEE: 821, + CORVISQUIRE: 822, + CORVIKNIGHT: 823, + BLIPBUG: 824, + DOTTLER: 825, + ORBEETLE: 826, + NICKIT: 827, + THIEVUL: 828, + GOSSIFLEUR: 829, + ELDEGOSS: 830, + WOOLOO: 831, + DUBWOOL: 832, + CHEWTLE: 833, + DREDNAW: 834, + YAMPER: 835, + BOLTUND: 836, + ROLYCOLY: 837, + CARKOL: 838, + COALOSSAL: 839, + APPLIN: 840, + FLAPPLE: 841, + APPLETUN: 842, + SILICOBRA: 843, + SANDACONDA: 844, + CRAMORANT: 845, + ARROKUDA: 846, + BARRASKEWDA: 847, + TOXEL: 848, + TOXTRICITY: 849, + SIZZLIPEDE: 850, + CENTISKORCH: 851, + CLOBBOPUS: 852, + GRAPPLOCT: 853, + SINISTEA: 854, + POLTEAGEIST: 855, + HATENNA: 856, + HATTREM: 857, + HATTERENE: 858, + IMPIDIMP: 859, + MORGREM: 860, + GRIMMSNARL: 861, + OBSTAGOON: 862, + PERRSERKER: 863, + CURSOLA: 864, + SIRFETCHD: 865, + MR_RIME: 866, + RUNERIGUS: 867, + MILCERY: 868, + ALCREMIE: 869, + FALINKS: 870, + PINCURCHIN: 871, + SNOM: 872, + FROSMOTH: 873, + STONJOURNER: 874, + EISCUE: 875, + INDEEDEE: 876, + MORPEKO: 877, + CUFANT: 878, + COPPERAJAH: 879, + DRACOZOLT: 880, + ARCTOZOLT: 881, + DRACOVISH: 882, + ARCTOVISH: 883, + DURALUDON: 884, + DREEPY: 885, + DRAKLOAK: 886, + DRAGAPULT: 887, + ZACIAN: 888, + ZAMAZENTA: 889, + ETERNATUS: 890, + KUBFU: 891, + URSHIFU: 892, + ZARUDE: 893, + REGIELEKI: 894, + REGIDRAGO: 895, + GLASTRIER: 896, + SPECTRIER: 897, + CALYREX: 898, + WYRDEER: 899, + KLEAVOR: 900, + URSALUNA: 901, + BASCULEGION: 902, + SNEASLER: 903, + OVERQWIL: 904, + ENAMORUS: 905, + SPRIGATITO: 906, + FLORAGATO: 907, + MEOWSCARADA: 908, + FUECOCO: 909, + CROCALOR: 910, + SKELEDIRGE: 911, + QUAXLY: 912, + QUAXWELL: 913, + QUAQUAVAL: 914, + LECHONK: 915, + OINKOLOGNE: 916, + TAROUNTULA: 917, + SPIDOPS: 918, + NYMBLE: 919, + LOKIX: 920, + PAWMI: 921, + PAWMO: 922, + PAWMOT: 923, + TANDEMAUS: 924, + MAUSHOLD: 925, + FIDOUGH: 926, + DACHSBUN: 927, + SMOLIV: 928, + DOLLIV: 929, + ARBOLIVA: 930, + SQUAWKABILLY: 931, + NACLI: 932, + NACLSTACK: 933, + GARGANACL: 934, + CHARCADET: 935, + ARMAROUGE: 936, + CERULEDGE: 937, + TADBULB: 938, + BELLIBOLT: 939, + WATTREL: 940, + KILOWATTREL: 941, + MASCHIFF: 942, + MABOSSTIFF: 943, + SHROODLE: 944, + GRAFAIAI: 945, + BRAMBLIN: 946, + BRAMBLEGHAST: 947, + TOEDSCOOL: 948, + TOEDSCRUEL: 949, + KLAWF: 950, + CAPSAKID: 951, + SCOVILLAIN: 952, + RELLOR: 953, + RABSCA: 954, + FLITTLE: 955, + ESPATHRA: 956, + TINKATINK: 957, + TINKATUFF: 958, + TINKATON: 959, + WIGLETT: 960, + WUGTRIO: 961, + BOMBIRDIER: 962, + FINIZEN: 963, + PALAFIN: 964, + VAROOM: 965, + REVAVROOM: 966, + CYCLIZAR: 967, + ORTHWORM: 968, + GLIMMET: 969, + GLIMMORA: 970, + GREAVARD: 971, + HOUNDSTONE: 972, + FLAMIGO: 973, + CETODDLE: 974, + CETITAN: 975, + VELUZA: 976, + DONDOZO: 977, + TATSUGIRI: 978, + ANNIHILAPE: 979, + CLODSIRE: 980, + FARIGIRAF: 981, + DUDUNSPARCE: 982, + KINGAMBIT: 983, + GREAT_TUSK: 984, + SCREAM_TAIL: 985, + BRUTE_BONNET: 986, + FLUTTER_MANE: 987, + SLITHER_WING: 988, + SANDY_SHOCKS: 989, + IRON_TREADS: 990, + IRON_BUNDLE: 991, + IRON_HANDS: 992, + IRON_JUGULIS: 993, + IRON_MOTH: 994, + IRON_THORNS: 995, + FRIGIBAX: 996, + ARCTIBAX: 997, + BAXCALIBUR: 998, + GIMMIGHOUL: 999, + GHOLDENGO: 1000, + WO_CHIEN: 1001, + CHIEN_PAO: 1002, + TING_LU: 1003, + CHI_YU: 1004, + ROARING_MOON: 1005, + IRON_VALIANT: 1006, + KORAIDON: 1007, + MIRAIDON: 1008, + WALKING_WAKE: 1009, + IRON_LEAVES: 1010, + DIPPLIN: 1011, + POLTCHAGEIST: 1012, + SINISTCHA: 1013, + OKIDOGI: 1014, + MUNKIDORI: 1015, + FEZANDIPITI: 1016, + OGERPON: 1017, + ARCHALUDON: 1018, + HYDRAPPLE: 1019, + GOUGING_FIRE: 1020, + RAGING_BOLT: 1021, + IRON_BOULDER: 1022, + IRON_CROWN: 1023, + TERAPAGOS: 1024, + PECHARUNT: 1025, + ALOLA_RATTATA: 2019, + ALOLA_RATICATE: 2020, + ALOLA_RAICHU: 2026, + ALOLA_SANDSHREW: 2027, + ALOLA_SANDSLASH: 2028, + ALOLA_VULPIX: 2037, + ALOLA_NINETALES: 2038, + ALOLA_DIGLETT: 2050, + ALOLA_DUGTRIO: 2051, + ALOLA_MEOWTH: 2052, + ALOLA_PERSIAN: 2053, + ALOLA_GEODUDE: 2074, + ALOLA_GRAVELER: 2075, + ALOLA_GOLEM: 2076, + ALOLA_GRIMER: 2088, + ALOLA_MUK: 2089, + ALOLA_EXEGGUTOR: 2103, + ALOLA_MAROWAK: 2105, + ETERNAL_FLOETTE: 2670, + GALAR_MEOWTH: 4052, + GALAR_PONYTA: 4077, + GALAR_RAPIDASH: 4078, + GALAR_SLOWPOKE: 4079, + GALAR_SLOWBRO: 4080, + GALAR_FARFETCHD: 4083, + GALAR_WEEZING: 4110, + GALAR_MR_MIME: 4122, + GALAR_ARTICUNO: 4144, + GALAR_ZAPDOS: 4145, + GALAR_MOLTRES: 4146, + GALAR_SLOWKING: 4199, + GALAR_CORSOLA: 4222, + GALAR_ZIGZAGOON: 4263, + GALAR_LINOONE: 4264, + GALAR_DARUMAKA: 4554, + GALAR_DARMANITAN: 4555, + GALAR_YAMASK: 4562, + GALAR_STUNFISK: 4618, + HISUI_GROWLITHE: 6058, + HISUI_ARCANINE: 6059, + HISUI_VOLTORB: 6100, + HISUI_ELECTRODE: 6101, + HISUI_TYPHLOSION: 6157, + HISUI_QWILFISH: 6211, + HISUI_SNEASEL: 6215, + HISUI_SAMUROTT: 6503, + HISUI_LILLIGANT: 6549, + HISUI_ZORUA: 6570, + HISUI_ZOROARK: 6571, + HISUI_BRAVIARY: 6628, + HISUI_SLIGGOO: 6705, + HISUI_GOODRA: 6706, + HISUI_AVALUGG: 6713, + HISUI_DECIDUEYE: 6724, + PALDEA_TAUROS: 8128, + PALDEA_WOOPER: 8194, + BLOODMOON_URSALUNA: 8901, +}; + +// export default Species; \ No newline at end of file diff --git a/content/maps/abilityMap.js b/content/maps/abilityMap.js new file mode 100644 index 0000000..36dcc17 --- /dev/null +++ b/content/maps/abilityMap.js @@ -0,0 +1,315 @@ +window["__AbilityMap"] = { + NONE: 0, + STENCH: 1, + DRIZZLE: 2, + SPEED_BOOST: 3, + BATTLE_ARMOR: 4, + STURDY: 5, + DAMP: 6, + LIMBER: 7, + SAND_VEIL: 8, + STATIC: 9, + VOLT_ABSORB: 10, + WATER_ABSORB: 11, + OBLIVIOUS: 12, + CLOUD_NINE: 13, + COMPOUND_EYES: 14, + INSOMNIA: 15, + COLOR_CHANGE: 16, + IMMUNITY: 17, + FLASH_FIRE: 18, + SHIELD_DUST: 19, + OWN_TEMPO: 20, + SUCTION_CUPS: 21, + INTIMIDATE: 22, + SHADOW_TAG: 23, + ROUGH_SKIN: 24, + WONDER_GUARD: 25, + LEVITATE: 26, + EFFECT_SPORE: 27, + SYNCHRONIZE: 28, + CLEAR_BODY: 29, + NATURAL_CURE: 30, + LIGHTNING_ROD: 31, + SERENE_GRACE: 32, + SWIFT_SWIM: 33, + CHLOROPHYLL: 34, + ILLUMINATE: 35, + TRACE: 36, + HUGE_POWER: 37, + POISON_POINT: 38, + INNER_FOCUS: 39, + MAGMA_ARMOR: 40, + WATER_VEIL: 41, + MAGNET_PULL: 42, + SOUNDPROOF: 43, + RAIN_DISH: 44, + SAND_STREAM: 45, + PRESSURE: 46, + THICK_FAT: 47, + EARLY_BIRD: 48, + FLAME_BODY: 49, + RUN_AWAY: 50, + KEEN_EYE: 51, + HYPER_CUTTER: 52, + PICKUP: 53, + TRUANT: 54, + HUSTLE: 55, + CUTE_CHARM: 56, + PLUS: 57, + MINUS: 58, + FORECAST: 59, + STICKY_HOLD: 60, + SHED_SKIN: 61, + GUTS: 62, + MARVEL_SCALE: 63, + LIQUID_OOZE: 64, + OVERGROW: 65, + BLAZE: 66, + TORRENT: 67, + SWARM: 68, + ROCK_HEAD: 69, + DROUGHT: 70, + ARENA_TRAP: 71, + VITAL_SPIRIT: 72, + WHITE_SMOKE: 73, + PURE_POWER: 74, + SHELL_ARMOR: 75, + AIR_LOCK: 76, + TANGLED_FEET: 77, + MOTOR_DRIVE: 78, + RIVALRY: 79, + STEADFAST: 80, + SNOW_CLOAK: 81, + GLUTTONY: 82, + ANGER_POINT: 83, + UNBURDEN: 84, + HEATPROOF: 85, + SIMPLE: 86, + DRY_SKIN: 87, + DOWNLOAD: 88, + IRON_FIST: 89, + POISON_HEAL: 90, + ADAPTABILITY: 91, + SKILL_LINK: 92, + HYDRATION: 93, + SOLAR_POWER: 94, + QUICK_FEET: 95, + NORMALIZE: 96, + SNIPER: 97, + MAGIC_GUARD: 98, + NO_GUARD: 99, + STALL: 100, + TECHNICIAN: 101, + LEAF_GUARD: 102, + KLUTZ: 103, + MOLD_BREAKER: 104, + SUPER_LUCK: 105, + AFTERMATH: 106, + ANTICIPATION: 107, + FOREWARN: 108, + UNAWARE: 109, + TINTED_LENS: 110, + FILTER: 111, + SLOW_START: 112, + SCRAPPY: 113, + STORM_DRAIN: 114, + ICE_BODY: 115, + SOLID_ROCK: 116, + SNOW_WARNING: 117, + HONEY_GATHER: 118, + FRISK: 119, + RECKLESS: 120, + MULTITYPE: 121, + FLOWER_GIFT: 122, + BAD_DREAMS: 123, + PICKPOCKET: 124, + SHEER_FORCE: 125, + CONTRARY: 126, + UNNERVE: 127, + DEFIANT: 128, + DEFEATIST: 129, + CURSED_BODY: 130, + HEALER: 131, + FRIEND_GUARD: 132, + WEAK_ARMOR: 133, + HEAVY_METAL: 134, + LIGHT_METAL: 135, + MULTISCALE: 136, + TOXIC_BOOST: 137, + FLARE_BOOST: 138, + HARVEST: 139, + TELEPATHY: 140, + MOODY: 141, + OVERCOAT: 142, + POISON_TOUCH: 143, + REGENERATOR: 144, + BIG_PECKS: 145, + SAND_RUSH: 146, + WONDER_SKIN: 147, + ANALYTIC: 148, + ILLUSION: 149, + IMPOSTER: 150, + INFILTRATOR: 151, + MUMMY: 152, + MOXIE: 153, + JUSTIFIED: 154, + RATTLED: 155, + MAGIC_BOUNCE: 156, + SAP_SIPPER: 157, + PRANKSTER: 158, + SAND_FORCE: 159, + IRON_BARBS: 160, + ZEN_MODE: 161, + VICTORY_STAR: 162, + TURBOBLAZE: 163, + TERAVOLT: 164, + AROMA_VEIL: 165, + FLOWER_VEIL: 166, + CHEEK_POUCH: 167, + PROTEAN: 168, + FUR_COAT: 169, + MAGICIAN: 170, + BULLETPROOF: 171, + COMPETITIVE: 172, + STRONG_JAW: 173, + REFRIGERATE: 174, + SWEET_VEIL: 175, + STANCE_CHANGE: 176, + GALE_WINGS: 177, + MEGA_LAUNCHER: 178, + GRASS_PELT: 179, + SYMBIOSIS: 180, + TOUGH_CLAWS: 181, + PIXILATE: 182, + GOOEY: 183, + AERILATE: 184, + PARENTAL_BOND: 185, + DARK_AURA: 186, + FAIRY_AURA: 187, + AURA_BREAK: 188, + PRIMORDIAL_SEA: 189, + DESOLATE_LAND: 190, + DELTA_STREAM: 191, + STAMINA: 192, + WIMP_OUT: 193, + EMERGENCY_EXIT: 194, + WATER_COMPACTION: 195, + MERCILESS: 196, + SHIELDS_DOWN: 197, + STAKEOUT: 198, + WATER_BUBBLE: 199, + STEELWORKER: 200, + BERSERK: 201, + SLUSH_RUSH: 202, + LONG_REACH: 203, + LIQUID_VOICE: 204, + TRIAGE: 205, + GALVANIZE: 206, + SURGE_SURFER: 207, + SCHOOLING: 208, + DISGUISE: 209, + BATTLE_BOND: 210, + POWER_CONSTRUCT: 211, + CORROSION: 212, + COMATOSE: 213, + QUEENLY_MAJESTY: 214, + INNARDS_OUT: 215, + DANCER: 216, + BATTERY: 217, + FLUFFY: 218, + DAZZLING: 219, + SOUL_HEART: 220, + TANGLING_HAIR: 221, + RECEIVER: 222, + POWER_OF_ALCHEMY: 223, + BEAST_BOOST: 224, + RKS_SYSTEM: 225, + ELECTRIC_SURGE: 226, + PSYCHIC_SURGE: 227, + MISTY_SURGE: 228, + GRASSY_SURGE: 229, + FULL_METAL_BODY: 230, + SHADOW_SHIELD: 231, + PRISM_ARMOR: 232, + NEUROFORCE: 233, + INTREPID_SWORD: 234, + DAUNTLESS_SHIELD: 235, + LIBERO: 236, + BALL_FETCH: 237, + COTTON_DOWN: 238, + PROPELLER_TAIL: 239, + MIRROR_ARMOR: 240, + GULP_MISSILE: 241, + STALWART: 242, + STEAM_ENGINE: 243, + PUNK_ROCK: 244, + SAND_SPIT: 245, + ICE_SCALES: 246, + RIPEN: 247, + ICE_FACE: 248, + POWER_SPOT: 249, + MIMICRY: 250, + SCREEN_CLEANER: 251, + STEELY_SPIRIT: 252, + PERISH_BODY: 253, + WANDERING_SPIRIT: 254, + GORILLA_TACTICS: 255, + NEUTRALIZING_GAS: 256, + PASTEL_VEIL: 257, + HUNGER_SWITCH: 258, + QUICK_DRAW: 259, + UNSEEN_FIST: 260, + CURIOUS_MEDICINE: 261, + TRANSISTOR: 262, + DRAGONS_MAW: 263, + CHILLING_NEIGH: 264, + GRIM_NEIGH: 265, + AS_ONE_GLASTRIER: 266, + AS_ONE_SPECTRIER: 267, + LINGERING_AROMA: 268, + SEED_SOWER: 269, + THERMAL_EXCHANGE: 270, + ANGER_SHELL: 271, + PURIFYING_SALT: 272, + WELL_BAKED_BODY: 273, + WIND_RIDER: 274, + GUARD_DOG: 275, + ROCKY_PAYLOAD: 276, + WIND_POWER: 277, + ZERO_TO_HERO: 278, + COMMANDER: 279, + ELECTROMORPHOSIS: 280, + PROTOSYNTHESIS: 281, + QUARK_DRIVE: 282, + GOOD_AS_GOLD: 283, + VESSEL_OF_RUIN: 284, + SWORD_OF_RUIN: 285, + TABLETS_OF_RUIN: 286, + BEADS_OF_RUIN: 287, + ORICHALCUM_PULSE: 288, + HADRON_ENGINE: 289, + OPPORTUNIST: 290, + CUD_CHEW: 291, + SHARPNESS: 292, + SUPREME_OVERLORD: 293, + COSTAR: 294, + TOXIC_DEBRIS: 295, + ARMOR_TAIL: 296, + EARTH_EATER: 297, + MYCELIUM_MIGHT: 298, + MINDS_EYE: 299, + SUPERSWEET_SYRUP: 300, + HOSPITALITY: 301, + TOXIC_CHAIN: 302, + EMBODY_ASPECT_TEAL: 303, + EMBODY_ASPECT_WELLSPRING: 304, + EMBODY_ASPECT_HEARTHFLAME: 305, + EMBODY_ASPECT_CORNERSTONE: 306, + TERA_SHIFT: 307, + TERA_SHELL: 308, + TERAFORM_ZERO: 309, + POISON_PUPPETEER: 310 +}; + +// export default AbilityMap; \ No newline at end of file diff --git a/content/maps/natureMap.js b/content/maps/natureMap.js new file mode 100644 index 0000000..bbe92c1 --- /dev/null +++ b/content/maps/natureMap.js @@ -0,0 +1,29 @@ +window["__NatureMap"] = { + HARDY: 0, + LONELY: 1, + BRAVE: 2, + ADAMANT: 3, + NAUGHTY: 4, + BOLD: 5, + DOCILE: 6, + RELAXED: 7, + IMPISH: 8, + LAX: 9, + TIMID: 10, + HASTY: 11, + SERIOUS: 12, + JOLLY: 13, + NAIVE: 14, + MODEST: 15, + MILD: 16, + QUIET: 17, + BASHFUL: 18, + RASH: 19, + CALM: 20, + GENTLE: 21, + SASSY: 22, + CAREFUL: 23, + QUIRKY: 24 +}; + +// export default NatureMap; \ No newline at end of file diff --git a/content/maps/weatherMap.js b/content/maps/weatherMap.js new file mode 100644 index 0000000..a5a61be --- /dev/null +++ b/content/maps/weatherMap.js @@ -0,0 +1,14 @@ +window["__WeatherMap"] = { + NONE: 0, + SUNNY: 1, + RAIN: 2, + SANDSTORM: 3, + HAIL: 4, + SNOW: 5, + FOG: 6, + HEAVY_RAIN: 7, + HARSH_SUN: 8, + STRONG_WINDS: 9 +}; + +// export default WeatherMap; \ No newline at end of file diff --git a/content/util_classes/localStorage.util.js b/content/util_classes/localStorage.util.js new file mode 100644 index 0000000..2096cd0 --- /dev/null +++ b/content/util_classes/localStorage.util.js @@ -0,0 +1,207 @@ +// const browserApi = typeof browser !== "undefined" ? browser : chrome; +// import CryptoJS from '../libs/crypto-js.min'; + +class LocalStorageClass { + constructor() { + this.slotId = -1; + this.saveKey = "x0i2O7WRiANTqPmZ"; + this.sessionData = {}; + // LocalStorageClass.#init(this); + // this.dataKey; + // this.sessionKey; + // this.sessionId; + // + // this.potentialSessions = []; + // this.tempSaveSlot; + // this.clientSessionId; + } + + clearAllSessionData(){ + setTimeout(function() { + for (let key in localStorage) { + if (key.includes('sessionData')) localStorage.removeItem(key) + } + }, 1000) + } + + setSessionData(){ + let currentSessionData = {} + for (let key in localStorage) { + if ((this.slotId > 0 && key.includes(`sessionData${slotId}`)) || key.includes('sessionData')) { + currentSessionData = localStorage.getItem(key) + break + } + } + this.sessionData = JSON.parse(CryptoJS.AES.decrypt(currentSessionData, this.saveKey).toString(CryptoJS.enc.Utf8)) + console.log("Got session data", this.sessionData, "for slot id", this.slotId) + // browserApi.runtime.sendMessage({ type: 'BG_GET_SAVEDATA', data: this.sessionData, slotId: this.slotId }) + } + + getSessionData() { + return this.sessionData; + } + + async getExtensionSettings() { + return new Promise((resolve) => { + browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty'], (data) => { + if (data.showMinified === undefined) { + browserApi.storage.sync.set({ 'showMinified': false }); + data.showMinified = false; + } + if (data.scaleFactor === undefined) { + browserApi.storage.sync.set({ 'scaleFactor': 1 }); + data.scaleFactor = 1; + } + if (data.showEnemeies === undefined) { + browserApi.storage.sync.set({ 'showEnemies': true }); + data.showEnemeies = true; + } + if (data.showParty === undefined) { + browserApi.storage.sync.set({ 'showParty': true }); + data.showParty = true; + } + resolve(data); + }); + }); + } + + // static #init($this) { + // // LocalStorageClass.#extensionSettingsListener($this); + // $this.dataKey = $this.getDataKey("data_"); + // //$this.sessionKey = $this.getKey("sessionData"); + // LocalStorageClass.#getExtensionSettings($this); + // } + // + // getDataKey(matchString) { + // const keys = Object.keys(localStorage); + // for (let i = 0; i < keys.length; i++) { + // const key = keys[i]; + // if (key.includes(matchString)) { + // return key; + // } + // } + // } + // + // clearLocalSessionData() { + // const keys = Object.keys(localStorage); + // for (let i = 0; i < keys.length; i++) { + // const key = keys[i]; + // if (key.includes("sessionData")) { + // localStorage.removeItem(key); + // } + // } + // console.log("LocalStorage Primed"); + // } + // + // determineSession(){ + // let $this = this; + // let slot = $this.tempSaveSlot.slot; + // let dataToMatch = $this.tempSaveSlot.slot; + // console.log($this.potentialSessions); + // for(let sI in $this.potentialSessions) { + // let curSessionKey = $this.potentialSessions[sI]; + // console.log(curSessionKey); + // let curSessionData = curSessionKey.data; + // if (curSessionData == dataToMatch) { + // //return curSessionKey.key; + // $this.sessionKey = curSessionKey.key; + // } + // else{ + // console.log("NO MATCH WITH SLOT: ", slot) + // } + // } + // } + // + // getPotentialSessionKeys(){ + // const keys = Object.keys(localStorage); + // let potentialSessions = []; + // for (let i = 0; i < keys.length; i++) { + // const key = keys[i]; + // console.log(key); + // if (key.includes("sessionData")) { + // let data = this.readLocalDataByKey(key); + // console.log(data); + // let potentialSettingsObject = {key: key, data: data} + // potentialSessions.push(potentialSettingsObject); + // } + // } + // + // this.potentialSessions = potentialSessions + // return potentialSessions; + // } + // + // + // static async #getExtensionSettings($this) { + // return new Promise((resolve) => { + // browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty'], (data) => { + // if (data.showMinified === undefined) { + // browserApi.storage.sync.set({ 'showMinified': false }); + // data.showMinified = false; + // } + // if (data.scaleFactor === undefined) { + // browserApi.storage.sync.set({ 'scaleFactor': 1 }); + // data.scaleFactor = 1; + // } + // if (data.showEnemeies === undefined) { + // browserApi.storage.sync.set({ 'showEnemies': true }); + // data.showEnemeies = true; + // } + // if (data.showParty === undefined) { + // browserApi.storage.sync.set({ 'showParty': true }); + // data.showParty = true; + // } + // resolve(data); + // }); + // }); + // } + // + // + // + // async getExtensionSettings(){ + // return await LocalStorageClass.#getExtensionSettings(this); + // } + // + // getSessionData(){ + // + // + // let data = this.getPotentialSessionKeys(); + // this.sessionKey = (data[0]).key; + // //console.log(this.sessionKey); + // //this.sessionKey = "sessionData2_ProSnow" + // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary + // let localStorageData = localStorage.getItem(this.sessionKey); + // const decryptedString = CryptoJS.AES.decrypt(localStorageData, saveKey).toString(CryptoJS.enc.Utf8); + // return JSON.parse(decryptedString); + // } + // + // setSessionData(sessionData) { + // //hard set + // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary + // const jsonString = JSON.stringify(sessionData); + // const encryptedString = CryptoJS.AES.encrypt(jsonString, saveKey).toString(); + // localStorage.setItem(this.sessionKey, encryptedString); + // } + // + // getPlayerData(){ + // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary + // let localStorageData = localStorage.getItem(this.dataKey); + // const decryptedString = CryptoJS.AES.decrypt(localStorageData, saveKey).toString(CryptoJS.enc.Utf8); + // return JSON.parse(decryptedString); + // } + // + // readLocalDataByKey(key){ + // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary + // let localStorageData = localStorage.getItem(key); + // const decryptedString = CryptoJS.AES.decrypt(localStorageData, saveKey).toString(CryptoJS.enc.Utf8); + // return JSON.parse(decryptedString); + // } + // + // setPlayerData(playerData) { + // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary + // const jsonString = JSON.stringify(playerData); + // const encryptedString = CryptoJS.AES.encrypt(jsonString, saveKey).toString(); + // localStorage.setItem(this.dataKey, encryptedString); + // } +} + + diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js new file mode 100644 index 0000000..01b1646 --- /dev/null +++ b/content/util_classes/pokemonMapper.util.js @@ -0,0 +1,283 @@ +// import Species from "./Pokemon_To_Id"; +// import EvolutionMap from "./PokemonEvolutions"; +// import WeatherMap from "./weatherMap"; +// import AbilityMap from "./abilityMap"; +// import NatureMap from "./natureMap"; + +class PokemonMapperClass{ + constructor() { + this.P2I = window.__Species; + this.I2P; + this.EvoMap = window.__EvolutionMap; + this.PrevoMap; + this.W2I = window.__WeatherMap; + this.I2W; + this.A2I = window.__AbilityMap; + this.I2A; + this.N2I = window.__NatureMap; + this.I2N; + PokemonMapperClass.#init(this); + } + + static #init($this){ + //let $this = this; + $this.I2P = PokemonMapperClass.#calculateInverseMap($this.P2I); + $this.I2W = PokemonMapperClass.#calculateInverseMap($this.W2I); + $this.I2A = PokemonMapperClass.#calculateInverseMap($this.A2I); + $this.I2N = PokemonMapperClass.#calculateInverseMap($this.N2I); + $this.PrevoMap = PokemonMapperClass.#calcPrevolution($this.EvoMap); + // console.log($this.P2I); + // console.log($this.I2P); + // console.log($this.EvoMap); + // console.log($this.PrevoMap); + } + + static #calculateInverseMap(map){ + console.log(map); + let returnMap = {}; + for (const [key, value] of Object.entries(map)) { + returnMap[value] = key; + } + return returnMap; + } + + static #calcPrevolution(evoMapT){ + // let evoMapT = window.__EvolutionMap; + let preEvolutions = {}; + const prevolutionKeys = Object.keys(evoMapT); + prevolutionKeys.forEach(pk =>{ + let evolutions = evoMapT[pk]; + if (Array.isArray(evolutions)) { + evolutions.forEach(evo => { + preEvolutions[evo.name] = pk; + }); + } else { + preEvolutions[evolutions.name] = pk; + } + }); + return preEvolutions; + } + + findBasePokemon(pokemonName) { + let currentName = pokemonName; + while (this.PrevoMap[currentName] !== undefined) { + currentName = this.PrevoMap[currentName]; + } + return currentName; + } + + static #mapPartyToPokemonArray(party) { + return party.map(pokemon => ({ + species: pokemon.species, + abilityIndex: pokemon.abilityIndex, + nature: pokemon.nature, + ivs: pokemon.ivs, + pokerus: pokemon.pokerus, + shiny: pokemon.shiny, + variant: pokemon.variant + })); + } + + static async #getPokeType(id) { + try { + const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`); + const data = await response.json(); + const types = data.types.map(type => type.type.name); + return types; + } catch (error) { + console.error('Error fetching Pokémon type:', error); + return null; + } + } + + static async #getPokemonTypeEffectiveness($this, id) { + const types = await PokemonMapperClass.#getPokeType(id); + if (types) { + const { weaknesses, resistances, immunities } = await PokemonMapperClass.#calculateTypeEffectiveness($this, types); + return { + 'weaknesses': weaknesses, + 'resistances': resistances, + 'immunities': immunities + } + } + return {} + } + + async getTypeEffectiveness(type) { + try { + const response = await fetch(`https://pokeapi.co/api/v2/type/${type}`); + const data = await response.json(); + return data.damage_relations; + } catch (error) { + console.error(`Error fetching type effectiveness for ${type}:`, error); + return null; + } + } + + static async #calculateTypeEffectiveness($this, types) { + const typeEffectiveness = await Promise.all(types.map(type => $this.getTypeEffectiveness(type))); + if (typeEffectiveness.some(data => data === null)) { + return null; + } + + const weaknesses = new Set(); + const resistances = new Set(); + const immunities = new Set(); + + if (types.length === 1) { + const data = typeEffectiveness[0]; + data.double_damage_from.forEach(t => weaknesses.add(t.name)); + data.half_damage_from.forEach(t => resistances.add(t.name)); + data.no_damage_from.forEach(t => immunities.add(t.name)); + } else if (types.length === 2) { + const [type1, type2] = types; + const type1Effectiveness = typeEffectiveness[0]; + const type2Effectiveness = typeEffectiveness[1]; + + // Calculate weaknesses + type1Effectiveness.double_damage_from.forEach(t => { + if (!type2Effectiveness.half_damage_from.some(r => r.name === t.name)) { + weaknesses.add(t.name) + } + }); + type2Effectiveness.double_damage_from.forEach(t => { + if (!type1Effectiveness.half_damage_from.some(r => r.name === t.name)) { + weaknesses.add(t.name) + } + }); + + // Calculate resistances + type1Effectiveness.half_damage_from.forEach(t => { + if (!type2Effectiveness.double_damage_from.some(r => r.name === t.name)) { + resistances.add(t.name) + } + }); + + type2Effectiveness.half_damage_from.forEach(t => { + if (!type1Effectiveness.double_damage_from.some(r => r.name === t.name)) { + resistances.add(t.name) + } + }); + + // Calculate immunities + type1Effectiveness.no_damage_from.forEach(t => immunities.add(t.name)) + type2Effectiveness.no_damage_from.forEach(t => immunities.add(t.name)) + immunities.forEach(immunity => { + weaknesses.delete(immunity); + resistances.delete(immunity); + }) + } + + return { weaknesses, resistances, immunities }; + } + + async getPokemonArray(pokemonData, arena) { + let $this = this; + let pokemonArray = PokemonMapperClass.#mapPartyToPokemonArray(pokemonData); + let frontendPokemonArray = []; + let weather = {}; + + if (arena.weather && arena.weather.weatherType) { + weather = { + type: $this.I2W[arena.weather.weatherType], + turnsLeft: arena.weather.turnsLeft || 0, + }; + } + + const pokemonPromises = pokemonArray.map(async (pokemon) => { + const pokemonId = $this.I2P[$this.convertPokemonId(pokemon.species)].toLocaleLowerCase(); + const typeEffectiveness = await PokemonMapperClass.#getPokemonTypeEffectiveness($this, pokemonId); + let basePokemon = $this.findBasePokemon($this.I2P[pokemon.species]); + return { + id: pokemon.species, + name: $this.I2P[pokemon.species], + typeEffectiveness: { + weaknesses: Array.from(typeEffectiveness.weaknesses), + resistances: Array.from(typeEffectiveness.resistances), + immunities: Array.from(typeEffectiveness.immunities), + }, + ivs: pokemon.ivs, + ability: $this.I2A[pokemon.abilityIndex-1], + nature: $this.I2N[pokemon.nature], + basePokemon: basePokemon, + baseId: $this.P2I[basePokemon], + }; + }); + + frontendPokemonArray = await Promise.all(pokemonPromises); + + return { pokemon: frontendPokemonArray, weather: weather }; + } + + convertPokemonId(pokemonId) { + const conversionList = { + 2019: 10091, + 2020: 10092, + 2026: 10100, + 2027: 10101, + 2028: 10102, + 2037: 10103, + 2038: 10104, + 2050: 10105, + 2051: 10106, + 2052: 10107, + 2053: 10108, + 2074: 10109, + 2075: 10110, + 2076: 10111, + 2088: 10112, + 2089: 10113, + 2103: 10114, + 2105: 10115, + 2670: 10061, + 4052: 10162, + 4077: 10163, + 4078: 10164, + 4079: 10165, + 4080: 10166, + 4083: 10167, + 4110: 10168, + 4122: 10169, + 4144: 10170, + 4145: 10171, + 4146: 10172, + 4199: 10173, + 4222: 10174, + 4263: 10175, + 4264: 10176, + 4554: 10177, + 4555: 10178, + 4562: 10179, + 4618: 10180, + 6058: 10229, + 6059: 10230, + 6100: 10231, + 6101: 10232, + 6157: 10233, + 6211: 10234, + 6215: 10235, + 6503: 10236, + 6549: 10237, + 6570: 10238, + 6571: 10239, + 6628: 10240, + 6705: 10241, + 6706: 10242, + 6713: 10243, + 6724: 10244, + 8128: 10252, + 8194: 10253, + 8901: 10272 + } + if (pokemonId in conversionList) { + return conversionList[pokemonId] + } else { + return pokemonId + } + } +} + + +//const __PokemonMapper = new PokemonMapperClass(); + + diff --git a/content/utils.js b/content/utils.js new file mode 100644 index 0000000..eea59e3 --- /dev/null +++ b/content/utils.js @@ -0,0 +1,84 @@ +const contentInjectables = [ + "/content/maps/PokemonEvolutions.js", + "/content/maps/abilityMap.js", + "/content/maps/natureMap.js", + "/content/maps/Pokemon_To_Id.js", + "/content/maps/weatherMap.js", + "/content/util_classes/pokemonMapper.util.js", + "/content/util_classes/localStorage.util.js" +]; + +class UtilsClass extends EventTarget { + constructor() { + super(); + this.PokeMapper; + this.LocalStorage; + this.classesReady = { + "pokemonMapper.util.js": false, + "localStorage.util.js": false, + }; + this._isReady = false; // Use a private variable for the actual value + this.index = 0; + } + + get isReady() { + return this._isReady; + } + + set isReady(value) { + if (this._isReady !== value) { + this._isReady = value; + this.dispatchEvent(new Event('isReadyChange')); + } + } + + init() { + this.scriptInjector(); + } + + checkIfRead() { + let isReady = true; + for (let cI in this.classesReady) { + let targetClass = this.classesReady[cI]; + if (targetClass === false) { + isReady = false; + } + } + this.isReady = isReady; + } + + scriptInjector() { + if (this.index >= contentInjectables.length) { + console.log("All scripts injected."); + return; + } + + let targetScript = contentInjectables[this.index]; + console.log(`Injecting script: ${targetScript}`); + const scriptElem = document.createElement("script"); + scriptElem.src = chrome.runtime.getURL(targetScript); + scriptElem.type = "module"; + document.head.appendChild(scriptElem); + + scriptElem.addEventListener("load", () => { + console.log(`${targetScript} loaded.`); + if (targetScript === "/content/util_classes/pokemonMapper.util.js") { + this.classesReady["pokemonMapper.util.js"] = true; + this.PokeMapper = new PokemonMapperClass(); + this.checkIfRead(); + } else if (targetScript === "/content/util_classes/localStorage.util.js") { + this.classesReady["localStorage.util.js"] = true; + this.LocalStorage = new LocalStorageClass(); + this.checkIfRead(); + } else { + console.log(`Script ${targetScript} loaded but no special handling required.`); + } + this.index += 1; + this.scriptInjector(); // Inject the next script + }); + + scriptElem.addEventListener("error", (e) => { + console.error(`Failed to load script: ${targetScript}`, e); + }); + } +} diff --git a/fonts/pkmnems.ttf b/fonts/pkmnems.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2413162302122a074ac9cdfbfbaa0cfc2d05997e GIT binary patch literal 18164 zcmb_kYm8mhdHwEdULMbQJP(gwWClA9A@^7@hiL+aF?AgBmk|*Ew zCA0byINo&6_WSq0`6jNk8@`9*u6uSrc=!7|UwX}~W2f1B-`F*^ednpiKlvT}_8dN! z@4|_BALx1v`#;2I<*q%`hd%#o=Q+^-lv%A~_r4w5H(s^A3-n*XxkvVFKeXSzX;))^ z6xWaK-M(jP=3j4{G`sFDv+CFO@4J8c;_i?Ch1vBham_c3vg7mhZ$G&1gZZylMeM}<)0ep?(z1ps`z4mE)vC><)xN>df z&dOtzFIJwbyjVF^tyV9oZmdpMpQ*l7{YmZ8+Re4YwdZOlYp>Q<)~~Mbtv^}+=lYq( z%Eso#?#3gH&o*9ae7A9~M4|jdK>*=oNx{i1KuzRR`WA|O%k8~gFezE(z-Di46dv562(lg!jXwS1fCwjg= zuV>!n^R~=8H1D(Xo}Kp}y&b)m_HOCj+52ek(|AAMduINn^FK8I(fP;bpPWD2x2$ht z-{HO|`@Ycka^H9Qd-_-R-_ifk{>S>C>3^aBWdG~}Td-=u{sqqt*uWhF4-Y&&@XEr4 z3vXHY(86aIo*L{MynJxm;G=_I9y~Q-LUAxi@vbv)acOY9ixwoK0o?{#iNUFTKv%BFE5^5QeQH*mOQoO zbY|(R%X*hxyKL{Wr8TUGRY!~;@V|6*f5~?@c1yuVu0S0p`At_jOB9P%%W!fzoMa|@nr@*JH4X=0DN_#i7D7ciEjzc9VC@IFH zKiovlpRBd#=ErX2SO~$(-L~>`eQRa9<1p&uJn2b`$n4m4>mhSEg%6k@xDh*egFk>@^u4%b4wk;u`%d7g3tpMhU5_JkmMc#;lwlhKro5g3CzIHfTh1?&Jh zfC7XOdI@@70Gid=>MUZa&fkZ}CmC?Hqk*5{8jRI%1&~M_(BN5O5x!x}5{r~708i-C zrU`j;7rk5FX7mdGfgYk|+|ewYRe0#CG9Ds!GRM@8x=$6$ihI~<5b=hAkPWd0Q!1ny z$C)5#Z}M&zSMMnJ%car`d!2M4Hjrf?m&Kh$xz3JCq9|VcfmZ8un`JsOelKp}BuyK% zW`pb&wO3rIVSey%79+PTcDduM!PD)*{E7~9aGWTmQp!ZYqOMfTF?V8A?daK2*e3cI z@s_C(Y_#I<-ZcR+9AAMuhv3JocpdTj574YiE4+s3%SU*E!R2$>P=d#B3W2pq$`l*-w8J=U zLwKbV+M{TYuR2jXias**5r})GH6{jr>RV|D1^t|Ih5S#e7J`(-EV0(%Tv9dr(Q9_Z zI)jjYRHhW)mXy+zOJrI^JatvhQomBSejBo-HfHZkQN#+wW<&HF@{yMx4<|KNkQ>JE zz@hK>IeUV3ieaTxz?i1d;wRuH#P2}j$%F!q_yjdb5TgRM%Jl2USb5my=keKV1BTgy zvI>KrA0gB*WB>{av(~&BiJ(Oa7&u!vo$57KV{}dmQxgzl(PsGVg;6nQIhM+ zJeVYvlrErWK8S_{S~RLD@1hPh>F4Q^jhV_t)CW4GF<4nB#;h2KBWO)re)a^Su&nQ} zElJ)8`qt==6_d3Vjp-cuN$zo-&m9SA&@q-|q5SAMat8<3Qt>mV=~oC;$j_eJbwKo=e;U$OyvDDS&Ml}8Ja>&$v4JGs6w5Q-2ub6TOriE^QH z7qHK+k?MwEt=R+o$3D^|}yBrlqxRD!psLmDv2(t|vbBQ8TX zY)x?z^xQn`0ntIKj&~ymEpA5NzzSLdotJDMazc>C4UcV<1Q^hqE#ZOk47Exm492XG zTS-2YU}sPGq;Ad}pIZw#;qCTYG-?JH>Lg4$W*7sQMInZL_9%zKgoJRIuN1Ze?xmN~ zwL7oLZ5-ntG6=nQu)BKiG&;-yp;p8YrDDTd-&z=3VrJOR;(LWuHIx1mB(Vngm6W3>K}J=mP6R<2{TA} zsn=uf+kgxThRS--4%xkNoGB#DM#v$=yXKM6cgSCwHE|Wf(>vvDGyjn#Fx^1rDmJuz zc+EZg5nd8cbg39W$$CV`!TKpz*0&bx8EKBIK0*#BE2;=d{S|!-)gUqJiRO5`MzPQN zb-)qxP-uEIHqa=1GmF97~l{OvPr0h}`PMX=;fumU=P?tDtv6G8Gi%QCXHcYeR^sxD17K$}$j*9Q~~6n&%Yc z(*d!V|UKFmX&vZXxKuI8tSMKho&ZhSF`KoTvN@LVt`u%2QuteGeh z-RoK2hK=LAlGPh%@!*l7lv*#qg|S|1ImZ{qgaXEm4{>W2c}Ca@>nwTo z!cZ?40TfiyjaERtIsOtp&R^>>91;;5q9@t2vCIG=N`x$?cjpVmS*u_H8iD6By#tm4 zoW})63~)?SV$MGl2*Jmh-oAdyjKeg=p;~_MSoZ*OIFqj{EgQ%azJY&ZtdF2qTc!?^utJPT!hKP!+wmwZ&w0-?{ zGSQU~4ywf54q4`^-x!8$O72`ZZ)?-UIpi8TRzXgmCa3bCzSVskz!ncE3v;03qpr20 z%q~i#?&?I*^G=k`WsG#t3qq%IEr(%!;SHWD*K!J0L~(|n)K74&9CHg1frhfOrUR;7 zAzllpsP+|jjysf(`2jN))lAn>xnUhn1pAhFh9m@@;-qL1_kx*r=Hdvua)lQ5@Lb2W z1J0<>-%uHa03$7=4?-+Mz2lwo#x))elFP}J=nnaq*Z?P8H(&P^E)MoWfH^~0-`7%E z1wcld=ury5SCoSjy|k3gAKA0JkH{+TVLAWDeT?WG&<1rzlT^fMfJZHuIH-goz!gxz zZ2UoC5A}U50NtDBm9Dq<3S4V_7b6zrMOwK-9!ZV2(u;oeFpkb|jfSLO41{0<0b#9`}u)FdM?v3z%p0DqY z6_QYPNFqZByr4pOVQoIWRK!AXUDY>GHoEtyg3Zr0%_lm~(I3Dc<|h#! znwMT!uOj5+LF9Q09tVb0r-5810q;3tgDB+sFkiKVWq1fkYb^ot@cwVWYaj1lgdD5{ z;AJ3yPpSqJKz+xusL|YlHF4cUPc=nzD#5`U6GB9Jh0-OPx|o4%w5!KdJ_k$k`86RD zLmpRM3~NS=z7RUEkO8*T+o=vs8DY!_fX zML2s0*PpmTq-ZXQ_%F*ElogF&C-fz4@4t0!VrXyxNxGljE^a(!dGg>>Am@$cl(Wts z!Rc4GYB_Stk$s*>4);LnTeEwmT&usdR1?_Vz%iH($g>E{4JhvpQuUPb7CjbG#jK1M zssNfi2N({8I)Rqg#nZGie8y)SGCBPI<9lq~T(S_%ltHPE4S-U$tOLU|NknPF8SK(P z?F5SgQgFSRybh?Qq93K7s7a`+ z{#+9BOm&uma&e2)*?!>||CnHX{->Nxe{jCw&up>QFR|2X#Ec0U()ki!eU^&PX=*EQ&6}HT*Gdmm+aj{&r9iB6O8y^ zKNMrPH3E{Dnf}PydTPRN0|sH`#w2bbuj5bi2t<{j(Il^%v_vxEu7%!2vZveLcr{&K0j8Tz?2T|kR8PF_mrj7%a zWXTPaB#23HQ^J_P6hR?`3fKhTl=u!y2q0|GmxG+8)9s+X?>f_U4GT{oh1 z4jxU2XnB&0p5yDn*~Di_G8?veek!XuO)9nU0dLCCq??Rb(yn+GvV||!5|oWf{)_de ziG8yN=hT`Ok$e4CT`(|GZM1Q$L-EVyY6EbNxWS=hE*hkagGM2Px2??0K@opNs4A~2e7)3&FZq5?HNhe!wrdOs?1 z?#NuE3p~WS6Y!9XAvcv+)TZIaEk z*Nh-|ps)+O2LEsp)RL!>=R%hNq)1rVK)9gx>^vwg?*xee>v`;JxGtI2&|(c|%S6xl zDx4#X+k&Q3Wf;?!;fc8TkW#Q`n1k_|iHq`{hL7t^YU$HwgUT-faRLZQ^5u{Q2WDU| z4si+`ao5Zv**46m&{1YQf`u=bN61ITT+*L`ZtectspB>a=xfK3Fl?h&c%Gx+ISAY7 zx$E{>xEm=HttqHP`X#J|sT>RWN2A+D9nmz?ec_`E-++Txa08stO) zd^p-)d_0MB1RQ}Y)n-Kb@1l9;4m=i9E5It#;o+W zAVG{Mi)y}4=tJugQjw$+51@wtQXn|DptnE16jzYcy2L&p)7|IcMPHa2GR+sm^9CZH z&nR?vj&3dtBk<_)g>ZYR4KMxuk!&4jkS%?Fki7-3h4*oR=ZT_zwZ?_`v_xN1`xM;s zf8oV4k(EbeOcsz|KEHf21TnckqesU6DBWe zvf_JMxMDX>2l@)Bi|p$H@t$ndpu>JsAB(r8?59I=ig(d@f*)d*uduEl9{z>~lCh4UTR`7S&+^Wkv5JKOKY%H&<4K{d#sy!$vCm!ugKue3vb#d?K7jzgz70+U1o$xn#$? z$1Yp9?#i*vQ`1ui#%`S$+ciDC|LV1C4<0-?@xcCl_f74X+KXQ%cI?};cJsc2xaP(K zQ&W4#Zr`(g_wL)K?s;JM_5&^F*MuL|i0YbK*MP+pTc!@&fA7A%W9ui@M`q{Yg+F55 zfj{vbv&(Qxa2;;HjoD_KvT1w{VEVZ&;(bu>33~u%_Q3^HpfF{7 z!&*MZ5(cD1Q?F0t9ahG}?o@wQ(FpS0DCQbVfX-!z_ls~(WeoZJV$5?_V!e13o?p5I4!YFdga5Z+ z4b)f*H?4=F8|-In(k{0v;IymYn)li@_OpnZ_t{4KIs6X?KM&ciw;Sw6`vv<&yUBjZ zZnj^xTVSTm_A4;t?RJO#Dh%~&_UrZ=h==#vR{MZ$vk%%`aK{(z^Y(l83Hw`n+-B_& zd({5G{>=W;jzRjvcFI0(e{4TM-29>asr`PXX8&TZ*;Dpc_9OhyE>e%68h{!y(_W7wsSLzoLB8zGeSuciTVNar;O6Ye3-p_DA-zowRQQYX4>bZJ)Fc z!FBfmD7)dl&%uem1+X2k`vI0|ME5~EZHMe5_MrW?{f<3ke`9}cA47CMY`<&YvsdwV r%=Jp6W7mWGcTMf>+dp;S-hDegzNU6|+&zVmnyPaHFIDirMpXY767bIh literal 0 HcmV?d00001 diff --git a/images/menu/1/center.png b/images/menu/1/center.png new file mode 100755 index 0000000000000000000000000000000000000000..93d32cafafab35f6056c81857f96e0fd43c7dc22 GIT binary patch literal 821 zcmeAS@N?(olHy`uVBq!ia0vp^93afd3?%;@)H%Vxz*v~+>>QApoXo&backce~QEa(5;`+d$iTX7pNFYnt=V<((@vgU?|iGi`T_==ii-rRMw zUIdulo-;!#>__pQ`+?7X&E7D(`+x5&*SpsitnsRFFkU<7!-@|-yv~(WM(=R+Ue$eQ z`5{GbE|GnuUn?5t$NGu$o z_)&DKX|ix~iw5H{iKGc}yIzXl_MX8pchlqkAM4)#@Z2P{y3;iBXi_JOXHknw?6fz# zDx6DV)4D>p|KI;ROWJm#Q(3%-);yW#TY0s%E9`%1A>ZCN*`DdWa!iWX$D7PAs)cJe zFJb+Da6e!AbXDDb%+IAS{76_e?U!z4Y9$YIoZo^nu~+LCR_(j6`H|)E?+ezP439nd zPHxNT+W&{dr*@?OetpK(02l`f$sR$z3=CCj3=9n|3=F@3LJcn%7)pV1uM!v-tY$DU zh!@P+6=(yLU<>dGaW&Jm`~UxcT)ey&P=qnb+ueonKa=h~Acwug)7O>#1*?D9W! zm#+Zl=qQvHrz)fsrKaXoE}!+G38+I6rXwY_IJqdZpd>RtkD)lo-ATdI)!EF@(#%ZP zNY5~Q?JakpVkMa3+{C=nw8Z3+(xTKNOx4+QM1BHQOT$&?r=;d!Dr-&o2XZrmr>mdK II;Vst0I35wp#T5? literal 0 HcmV?d00001 diff --git a/images/menu/1/corner-bottom-left.png b/images/menu/1/corner-bottom-left.png new file mode 100755 index 0000000000000000000000000000000000000000..69d89030e3c46e109f61b814f177904ec477c975 GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iQ{If?z%Q+x^@wImQ@DE|NsBL$E>;$D92b5!yAlDJ)4HQ!Kba4#fxSlK!WK@{gAf%|EWGdpZ zVyR(=rlzK$ff^$xo1>#6LxBgY=8>7@S3nv{Tq8sji_} zh>?+%p|O>rnYMwkm4U&UBcTl_8glbfGSez?Yq&e}Ey#~*ARB;*(JDE=pt2}4J)?xd zFJA%9(NQQZPE|-NN=?nFTt4eV6HtdDOh-y;adJ^+K}lwQ9z$`EyOV;atFxJ*rJ0$o zk)C1r+FR~G#Y!;6xruqDX^F`trA4Vln5whqi2MYqmWHd&Pf5+eRMwjE59DSBPgg&e IbxsLQ0FM<%9RL6T literal 0 HcmV?d00001 diff --git a/images/menu/1/corner-bottom-right.png b/images/menu/1/corner-bottom-right.png new file mode 100755 index 0000000000000000000000000000000000000000..f9f7b306968d16064fbd1ac37fb34d0955fc2478 GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxB_W2T|0MOo8xAx5)u*-dX`lN#{d8SuY7nc4=Bf2666=m;PC85 z8i^mS!_!73oeDe*dVaTLCJ*2 zV~Hv=XL9mm5rxEO2Od0nbclhWY$98y%IsoMpbpg%*NBpo#FA92TG6c zX=bKtq-Pku_Le(Pu@X#iZem_(T4HiZX;Eqsrt0iDB0qturQxdcQ&MvmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2i7Er*<7TQ6dX{FocJ8`1|NsAAEwOYJP>!)A$S;_|;n|He z5GTpo-GyB&vEwz6!(QU)>&pIuRX~haK&~Uo8z`ja>Eal|aXmRfKtv=ZA;ioqO~8mv z=+H4YF9)ZitR6esm^wo^7#YGlSSNn3y1g5yL$$;;q9i4;B-JXpC>2OC7#SFu=o*;n z8k&U|8Ce+`TN#>Z8yH&|7_2!G+JK@VH$NpatrE9}yEET{JgEk<0hk)ClJg5Hi!#$Q zN*Mg|72q5lh0@|wg|wp7)SSxYvpzHdbtuAgq@)%n7iAWdWaj5F6bHFGDR{a%n;BY~ znduto8HTUDbP0l+XkKTvtj? literal 0 HcmV?d00001 diff --git a/images/menu/1/corner-top-right.png b/images/menu/1/corner-top-right.png new file mode 100755 index 0000000000000000000000000000000000000000..4a2981ba38178f1036ac732add0ec7bd540cde85 GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iQ{IfRR+cpdX{FocJ8`1|NsAI-8d6y4g+IJkY6x^!?PP{ zAWo9Ey9>KmV#jMBhrPtp*OmPRtAH49W! zm#+Zl=qQvHrz)fsrKaXoE}!+G38+I6rXwY_IJqdZpd>RtkD)lo-ATdI)!EF@(#%ZP zNY5~Q?JakpVkMa3+{C=nw8Z3+(xTKNOx4+QM1BHQOT$&?r=;d!Dr-&o2XZrmr>mdK II;Vst0L_|4c>n+a literal 0 HcmV?d00001 diff --git a/images/menu/1/edge-bottom.png b/images/menu/1/edge-bottom.png new file mode 100755 index 0000000000000000000000000000000000000000..a2dcb781c3d2fc43fc999ab57ad8e74e23ab302a GIT binary patch literal 847 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxSHwOMd(>p85kcoQ@@e0UwM0o>+Bt2amLpZJ{CpfS+IUHEP!oqXRfk82*fq_AZjk(lhQ_gFk zBGnSth?11Vl2ohYqEsNoU}RuqqHAEPYiJf?WMpM%Y-MPsZD4F=V6f&$C{QbshTQy= z%(P0}8t%?~3-W{-$Od3)vr5h{s4U7%&nRK=%U6JNbQDU9Qx(#RQd4s(m(Tjp1k|Aj z(~*)|oLrPyP?DLS$50&P?xf)9>TG6cX=bKtq-Pku_Le(Pu@X#iZem_(T4HiZX;Eqs krt0iDB0qturQxdcQ&MvmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxJpP!95+*S*R?Uzwfq17f8Dd!Vn8XzByV>Ymi~;Jfj|y>iKnkC z`wLb9F44NP?n%|eWftPG8<49&C+jI9g|)*K0KK+%w!pOTqYiCe?nnQuW3R|DAq zOkq~Z`303lnduoN41W0vaE^{bX>qDTT2X3hPUZ4hADVzV6k$42Qj3#|G7CyF^Ya*r zgWR1IJYAj53@y#fbdB^3!`I$&2P#&ADb7vID@{vGE-5WaEy7ftJxAmxP_;B%b$&`} W4yLl!lz$*MGkCiCxvXmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxSHwOx$D{-H&d06kof=qf9cCbASuQqZ+91#{*0S}Kn{C}r>`sf z3swO!UIDp|C~u&UfTxRN2*>s0goKcwGzA|92F(LZhQI4?e*ns zQmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxJpP!95+*~GBA$NvozDS`~Uy{%}o>zOmq!Qbq&ozjEt-djjasLv<-}{3=GyB32i{pkei>9 znO2Eg!`+#0LB3D}*#Jy#R>}DVl|`B986^yU`3i83jzVd1szO>(YHCj9@>w66fI1Xm zI#N=LlZ!G7N;32F7>a}3ofJG>oy`m_&CGO-^bEt--f{;jR)Q(cP0TAzOH3{)ElMrI kRGmFXn+HZ7F0pjwzguZ><` zf!gI>C8TZ8Rw#(t^jg$kP}`t&5EMlaty>qhskoi1ff9L!Gv}M%%sI@Q0c$v|Wb`^O zWU@Ie6!g0m7MEQ17i@Ilq=UYQqN_7=6JcuF$2}G^-g?Yhwa@))O|iJHfTclrOi{I* z@TBncdQLTYN4QN%MPkBd!u^_DQ25T&qh)?EIa%f}leKUt0M-^^SF(zuRjj16jIg{M zcP5=ze(z(x#1YTV&q?eS??fj=5I-)a7$?9mgN({Nj0YbBvZ6-5x0FB2n&c`ns}#^! zB}s}L{i5cjdR$^c^tg;P1+)Ku`>H2~eC6s6Kh!@P##;~Ax8b{J7@tRm@qG-oC%DX3 z^4AVwKmaz)MAP|QCv#q1hP3V^Q@g@3T zc?sVqTi~{W-Gpj~B+zI=il=)8Rp8bu^gv{0 zqT2A4gvaRyDcpKh1pVX~>Cj_-q7*&^StPJtWy5BIAxI4IQY1jgTOw^d;;9V2b2byy zt|n-LCiqLim0rcLt+UxS?S$XlioaAR{C9zou1esn1Zhyzh|g)rCkQww^mzm`6D`f7 azAbOE>`1Mc@hW@(0000>QApoXo&backce~QEa(5;`+d$iTX7pNFYnt=V<((@vgU?|iGi`T_==ii-rRMw zUIdulo-;!#>__pQ`+?7X&E7D(`+x5&*SpsitnsRFFkU<7!-@|-yv~(WM(=R+Ue$eQ z`5{GbE|GnuUn?5t$NGu$o z_)&DKX|ix~iw5H{iKGc}yIzXl_MX8pchlqkAM4)#@Z2P{y3;iBXi_JOXHknw?6fz# zDx6DV)4D>p|KI;ROWJm#Q(3%-);yW#TY0s%E9`%1A>ZCN*`DdWa!iWX$D7PAs)cJe zFJb+Da6e!AbXDDb%+IAS{76_e?U!z4Y9$YIoZo^nu~+LCR_(j6`H|)E?+ezP439nd zPHxNT+W&{dr*@?OetpK(02l`f$sR$z3=CCj3=9n|3=F@3LJcn%7)pV1uM!v-tY$DU zh!@P+6=(yLU<>dGaW&Jm`~UxcT)ey&P=qnb+ueonKa=h~Acwug)7O>#1*@PKA3uX& zvIJ0w+tbA{gyVX0f&(i9g8&2L!lQ}@fx@aKt`Q|Ei6yC4$wjF^iowXh$VAt`RM*fv z#L&{p(8S8nRNKJV%D}+OAiftxLvDUbW?Cg~4c58O4S^ceKsEr=lvQ$mL1j^9dPWI@ zU%mpIqoYt-oT`vkl$x4TxqQ}#CZG;Qn2wax;^d;tf|AVqJci;RcP9l;S7$RrOEWWF zBR#|LwYS`Xij`oBa})DQ(-MmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2355+aOf22ZbnOg119h@8{{R2acyL)5P>!)A$S;_|;n|He z5GTpo-GyB&vEwz6!(QU)>&pIuRZxtNpFuEL0w|>F>Eal|aXnce$fz)}K}b(%_B3*uYfd^xJHzuB$lLFB^RXvDF!10BNJT%Q(Z&z z5JO8VLlY}QQ*8rdD+2>BgZN$)4Y~O#nQ4`{HCX39Hw0=>1K9vfj8@6{1(ija=@}&q ze)$S;j*dcUajHUEQEF;Vk{nt(bKVLDP$i<65o3raHc^B9VQ+?^CWU7gJgEzQhy zjr0t|*WPjmDprCi&P~iKO-oEJDJ@DZ!c?6-N8~3^wKQCHeoAT%rn1(Qf1r3_@O1Ta JS?83{1OVS-MJxaS literal 0 HcmV?d00001 diff --git a/images/menu/2/corner-bottom-right.png b/images/menu/2/corner-bottom-right.png new file mode 100644 index 0000000000000000000000000000000000000000..1a1ca0c9cecee84047e0bcf36ba0d848c6f0af5a GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxB_W2T{{y?H-!x|BqSsZJp*;JGXDSnZ(p@6A1KFI666=m;PC85 z8i^mS!_!73=m$Il>`ECCc!^K@|x;kceGAYx>e*dVaTLCJ*2 zV~Hv=XL9mm5rxEO2Od0nbclhWY$98y%IsoMpbpg%*NBpo#FA92CwWnkcC5Z{ZUAvZrIGp!Q02J77Ch9EbAYyhT4tK|HG%A(Bl zj1mUFd<8g1N1?PhRUxe?H8rPl`K%93Kpl!O9Vw~B$wiq3C7Jno48=k2P70o`&Sr*| zW@frZdWPX^Z@B{%E5Q`!CgzoA&B{c_AS!>EaP{c5J My85}Sb4q9e086V#?EnA( literal 0 HcmV?d00001 diff --git a/images/menu/2/corner-top-left.png b/images/menu/2/corner-top-left.png new file mode 100644 index 0000000000000000000000000000000000000000..267dd133d4482d91deb875e8f7243abd53fd1378 GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX237xDAg$*+dJp;{j?My7){{R1fbnBg3pd4dKkY6x^!?PP{ zAWo9Ey9>KmV#jMBhrPtp*OmPRtDqPkKZ9Vh1W-uL)5S4_<9c#}fQU#+LWr4Jnt&0T z(4k{)UJg!2Sv_{NF?EJ;FfxR9uulA5b$d5ZhiZvyL`h0wNvc(HQ7VvPFfuSQ(KRsD zH8c+~w6robu`)E(HZZm_Fz_;n??us&o1c=IR*74Kb?$RRkefg@08^t?a(+Q&QD%BZ z34>q00-U3xP+FX-kXDqMnp3%a)`upb4n>%bl+@znqRfJl%=|ot;vjb?1y5IJGeb)= zGhHJ+!|=7Y+<}UfV2X1S^GeealS@jAQj0KEXU`G&2~;f&SDl}dnuDpVHRT^DVi-JK L{an^LB{Ts5$OB0i literal 0 HcmV?d00001 diff --git a/images/menu/2/corner-top-right.png b/images/menu/2/corner-top-right.png new file mode 100644 index 0000000000000000000000000000000000000000..26cabf845cf358aec28cfb72bd471d170cbb0d33 GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2355+abh0uGJp;{j?My7){{R2K(M8q}D92b59nO2EggLUq6ko(m@HUJZ&RdRkoWl?5&MhSyo zz5<-1qflC$s*qNcnwnF&eAb61pbkZtj+E5mk>m0*f<6Z1;b5|c|xi&Bd)RcFr;`3Y1l4Og9?lA435tTp8yC|(#mUHx3v IIVCg!0FVMiC;$Ke literal 0 HcmV?d00001 diff --git a/images/menu/2/edge-bottom.png b/images/menu/2/edge-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..cd3300cfbf43f8bde6d52ca0222d66a579185123 GIT binary patch literal 847 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxSHwO8F~ilWMwF9m?0q{@&Et-k7v51fU=B9-tI1}Kk{E52Xfd; zJbhi+U$6>_@$oYVCQAT?Bt2amLpZJ{CpfS+IUHEP!oqXRfk82*fq_AZjk(lhQ_gFk zBGnSth?11Vl2ohYqEsNoU}RuqqHAEPYiJ%~XlZ3=Vr6KmZD4F=VBlpC-;1IlH$Npa ztrE8e>)hvtKn-dj8-S_JDmlNPvM4h>qlCdPUjfe1Q7A1=RY)sJP0guXKI=mhP=_K+ zM@njOa#3bMNoIZ?LvfJ1lY*zKvzei#nVGJUo?-afTkb%`N-)K_iFu`IiOD6UMX5!Y jsa`~<3&hO5p`NzK7j)|&DU6z~k5u6{1-oD!M<3&TIp literal 0 HcmV?d00001 diff --git a/images/menu/2/edge-left.png b/images/menu/2/edge-left.png new file mode 100644 index 0000000000000000000000000000000000000000..7d1ba041d1c5baad7297127e8022b59b6eaf7876 GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxJpP!C~TNvV(Dh4Yxn>E|N8|S8-P-bN#5=*Ed3cb1A!d&5>H=O z_7|*zVto7zg2@sf3wZt`|BqgyV)hf9t z6-Y4{85o)98kp)Dnui!#S{a&H8JcPv7+V<_cp1d^qG-s?PsvQH#I3^UMofvTn9s`FD) Wb1;>)ru+j1HiM_DpUXO@geCx5W;);i literal 0 HcmV?d00001 diff --git a/images/menu/2/edge-right.png b/images/menu/2/edge-right.png new file mode 100644 index 0000000000000000000000000000000000000000..7d5e482612104568973317f2ff76aa4e1ece717c GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxSHwOnOM3hY?vV-A@TqJ|KJ<4_CP7dByV>Ymi~;Jfj|y>iKnkC z`wLb%?vHg%yfbP0l+XkK9;Z9H literal 0 HcmV?d00001 diff --git a/images/menu/2/edge-top.png b/images/menu/2/edge-top.png new file mode 100644 index 0000000000000000000000000000000000000000..450a3fc61de790bca87df95917f89cb5b402f021 GIT binary patch literal 848 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxJpP!C~TOala*oU8EB?!_y7NY{|h`dKv~8lZ+92gANenj13By^ zp1!W^FIWY|`1lzFlO=#cQl2i3Asp9}6BrmB6&eJ*91bM#u<+o>zOmq!Qbq&o!3@xn;O{@$}wGE7|3=F&s;(Jjv7WCJj{StaKeR2F5XXOuAbn+HZ7F0pjwzguZ><` zf!gI>C8TZ8Rw#(t^jg$kP}`t&5EMlaty>qhskoi1ff9L!Gv}M%%sI@Q0c$v|Wb`^O zWU@Ie6!g0m7MEQ17i@Ilq=UYQqN_7=6JcuF$2}G^-g?Yhwa@))O|iJHfTclrOi{I* z@TBncdQLTYN4QN%MPkBd!u^_DQ25T&qh)?EIa%f}leKUt0M-^^SF(zuRjj16jIg{M zcP5=ze(z(x#1YTV&q?eS??fj=5I-)a7$?9mgN({Nj0YbBvZ6-5x0FB2n&c`ns}#^! zB}s}L{i5cjdR$^c^tg;P1+)Ku`>H2~eC6s6Kh!@P##;~Ax8b{J7@tRm@qG-oC%DX3 z^4AVwKmN5##FcgOWw2g}yG6-fBFVItT z7Ek1fO6Qy+H|Su8S5R<>Ad1vM3z}pK=_38d2k-krhWugpL@6~OVTgzUKrzBs`yFgm zCV>lWfVvroh~=r_0C3+b$c039><$G04=%Kc0)KOCRRVSMz9JXS+dfJlwDAt>33%Is zcjqWUD49FRFV|>TXx9^@&McS(v*0fUPq~bSg?7Ey^s!k-3qre|z*c3F!ub)nMUkRD rg*LbWV8Aq`f2tc05o6>QApoXo&backce~QEa(5;`+d$iTX7pNFYnt=V<((@vgU?|iGi`T_==ii-rRMw zUIdulo-;!#>__pQ`+?7X&E7D(`+x5&*SpsitnsRFFkU<7!-@|-yv~(WM(=R+Ue$eQ z`5{GbE|GnuUn?5t$NGu$o z_)&DKX|ix~iw5H{iKGc}yIzXl_MX8pchlqkAM4)#@Z2P{y3;iBXi_JOXHknw?6fz# zDx6DV)4D>p|KI;ROWJm#Q(3%-);yW#TY0s%E9`%1A>ZCN*`DdWa!iWX$D7PAs)cJe zFJb+Da6e!AbXDDb%+IAS{76_e?U!z4Y9$YIoZo^nu~+LCR_(j6`H|)E?+ezP439nd zPHxNT+W&{dr*@?OetpK(02l`f$sR$z3=CCj3=9n|3=F@3LJcn%7)pV1uM!v-tY$DU zh!@P+6=(yLU<>dGaW&Jm`~UxcT)ey&P=qnb+ueonKa=h~Acwug)7O>#1*@R2wyNo* z9fyEI+@3CuAsp9}6C79>7z7v?7amnS2ozQ=ag8WRNi0dVN-jzTQVd20Mkcxjrn-ja zA%>P#CdO9A=Gq3vRt5$ literal 0 HcmV?d00001 diff --git a/images/menu/3/corner-bottom-left.png b/images/menu/3/corner-bottom-left.png new file mode 100755 index 0000000000000000000000000000000000000000..6ec7eeeb5a2b0cd0d009df2015acf212b12afe65 GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iR;&|yV&@c>DomG#W&Wr{r~@8T4K){pd4dKkY6x^!?PP{ zAWo9Ey9>KmV#jMBhrPtp*OmPRtDvy9s_CR1hk!z=o-U3d9M_Wtf{Y3i8-x@UluSiD zRxCB_(A3m4G*DyYWOHRdP`(kYX@0Ff!3KFx53Q z4>7c~GBLI?HrF;VwlXl_Vf^<9MMG|WN@iLmZVk0DZgD^jY9JeciP0)Kzo4=xGd-h( z!7pC{&e2gQElyQPD@skxsa!tmLlaPkB1}h0YH@N=WnD>p{1Fb zu92Q$_}W|UK*dTh#kq-jrD=)DC8b5FMVP9y=ZO3Ss+NYU&QD3r!Bp0o@(&a*44$rj JF6*2UngF7rNjU%j literal 0 HcmV?d00001 diff --git a/images/menu/3/corner-bottom-right.png b/images/menu/3/corner-bottom-right.png new file mode 100755 index 0000000000000000000000000000000000000000..a4c0f78f159e98fe3b281ea56f5202668834b193 GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxB_W2T{{;WpX=AJOGrpW2E{klw*CMAzp-EI1W=B#B*-tA!Qt7B zG!Q4r+uem-EV1J?ki%Z$>Fdh=f>lshTh(;Zjzd5pHBT4E5RU7~0wP9ci46ja9F$CW zJeH_3b0#N07EwricHqIIM?iID6WKadW*3VBb*PrOMwFx^mZVxG7o`Fz1|tI_6I}yS zT|@H_LrW_YV=H5GZ3AN~0|Oq$e~(Z!g+ipKY^;H;i~gfQgbkswWj<7MGS+d LtDnm{r-UW|lq*e9 literal 0 HcmV?d00001 diff --git a/images/menu/3/corner-top-left.png b/images/menu/3/corner-top-left.png new file mode 100755 index 0000000000000000000000000000000000000000..5597639dc6c93c61886d83d8ed66ca167f128d25 GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iN@Nt>({SG2F07{+PT>H{Qv)-?O5R&pd4dKkY6x^!?PP{ zAWo9Ey9>KmV#jMBhrPtp*OmPRtDvy9s_CR1hk!zAo-U3d9M_W*1Vltq5<<+((gcjy zgbp2Z^Kx)H%IdMBjj1z)gOMS;gLUHfs@uDPI#f$sBT7;dOH!?pi&B9UgOP!eiLQaE zuAzB|p{13Hv6Zp8wt=ygfdLQWzegwQIE~NJ%YDF3Kz@$;{7VC=POWQt)(jHZ!y| zGt)KFGYnsQ%N?j#38pwVF|RZ&F}b9)D76Svb@m*QpFq{paMk%KsX3U+T2uakB8I`! L)z4*}Q$iB}WEV_b literal 0 HcmV?d00001 diff --git a/images/menu/3/corner-top-right.png b/images/menu/3/corner-top-right.png new file mode 100755 index 0000000000000000000000000000000000000000..1892b2c67b161ec3460ac908ee524a663b1f3ede GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iR;&|H`caA2F07{+PT>H{Qv)d$4}lWpd4dKkY6x^!?PP{ zAWo9Ey9>KmV#jMBhrPtp*OmPRtDvy9s_CR1hk!z=o-U3d9M_WtL_|^&0)m3X7=*mq zc#gSwb@Aw(b5Js2acObnWQY=Dt*O#Br~_#zag8WRNi0dVN-jzTQVd20Mkcxjrn-ja zA%>P#CdO9A=Gq3vRt5$mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxSHwOMFzz;*0x>0eqBOB;{X5uwL!t4cx6oTc6VX@k^k~Iki%Z$ z>Fdh=f>lshTh(;Zjzd5pNlzEY5RU7~2@b4H4hI&nu<#snU{H){U|>*UV=gt>l=B*> zNVUW@q9i4;B-JXpC>2OC7#SFu=o*;n8k&a~T3VSHTN#^c8yH&|81OLudxWAPH$Npa ztrE9}+8DPupawON4Zzf9m7HHtS(KTcQNrMtuK?%hD3lhbDx?*qrsh;GpY@>$s6!E^ zBPF#sxhS)sBr`vcp*YChNx{?A+04+=%uLrv&oF%LEq9<|C79ye#Jtk9#N?9FqSPWx j)!B1IegaiX!&T>}q~>5MYfbqF3U~%jS3j3^P6mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxJpP!T)%$Z#m2`>*Y5xS|4%u77XhUhlf2zsSo$+=1_C+kC7!;n z>@Qdag|$^pC+#={6cX@saSY+Oo}3^OVwR@h!@ywI!R+`i%?y+vR7+eVN>UO_QmvAU zQh^kMk%5tku7Rnpp?Qd*rIm@Xm9e?Dfw7f=0T1K9M<^O{^HVa@DsgM5jd6%?vHg%yfbP0l+XkKmexKc literal 0 HcmV?d00001 diff --git a/images/menu/3/edge-right.png b/images/menu/3/edge-right.png new file mode 100755 index 0000000000000000000000000000000000000000..663d4cc801defa04842ab846d008a0156744b59b GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxSHwOx!CwzzkXdpLgN4b|J|~S6oFEVN#5=*Ed3cb1A!d&5>H=O z_7|*z!rH2)lXe^e3JG|+IEHXsPfkb(2})D&VPMcaz-0Kl{`Lo;oN9?{L`h0wNvc(H zQ7VvPFfuSQ(KRsDH8c+~w6roYwlX%?HZZm_FyLYQ_XtHpZhlH;S|x4`wJ~mSKn-dj z8-OXyDmlNPvM4h>qlCdPUjfe1Q7A1=RY)sJP0guXKI=mhP=_K+M@njOa#3bMNoIZ? zLvfJ1lY*zKvzei#nVGJUo?-afTkb%`N-)K_iFu`IiOD6UMX5!Ysa`~<3&hO5p` XNzK7j)|&DU6xa-&u6{1-oD!MmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxJpP!T)%$3v9>KTDBeuh?*IS)hP)}yfU=B9-tI1}Kk{E52Xfd; zJbhi+U$6=aYpa@0+HnXdB<1Pi7{YNqIe~%EQK3P=%i%x*4-1c;LxTc?<1<#?J3O4m zKvk+Gt`Q|Ei6yC4$wjF^iowXh$VAt`RM*fv#L&{p#MsK%T-(6d%D{k!@!um94Y~O# znQ4`{HPptq#Q`;_fouRKH>>3Qg36-I^o$Y)zkCHaM@ONwI8`C7C^a>wa`~(eO+X!r zFdZqW#mPmP1tppJc?`ut?oJAxuFhtLmS$$UMtX+fYj3#&6)V9M=O*TrrX?nqloq8H lVXDraBk~idS{kl8KP5E>Q(0@uKTyasc)I$ztaD0e0sz}ALDm2O literal 0 HcmV?d00001 diff --git a/images/menu/3/original.png b/images/menu/3/original.png new file mode 100644 index 0000000000000000000000000000000000000000..d3810b06e0c07e0730fc362c6cf79736d8532123 GIT binary patch literal 671 zcmV;Q0$}}#P)n+HZ7F0pjwzguZ><` zf!gI>C8TZ8Rw#(t^jg$kP}`t&5EMlaty>qhskoi1ff9L!Gv}M%%sI@Q0c$v|Wb`^O zWU@Ie6!g0m7MEQ17i@Ilq=UYQqN_7=6JcuF$2}G^-g?Yhwa@))O|iJHfTclrOi{I* z@TBncdQLTYN4QN%MPkBd!u^_DQ25T&qh)?EIa%f}leKUt0M-^^SF(zuRjj16jIg{M zcP5=ze(z(x#1YTV&q?eS??fj=5I-)a7$?9mgN({Nj0YbBvZ6-5x0FB2n&c`ns}#^! zB}s}L{i5cjdR$^c^tg;P1+)Ku`>H2~eC6s6Kh!@P##;~Ax8b{J7@tRm@qG-oC%DX3 z^4AVw`d1_lNOZCyB{NKNS zKZXm)0qBl&baZ53L07bD*?NW>S8tMK!K!8JF)YEb;KtRP40mteC(8nCfC*jT^{cmJ z8-`6Uh6U6HqZW)>FlxcDv_Mo$m~6wa>BT5bHMG^qwg8)63=6`d0;yKvz%4+pD5z0= z!W_x`<;$1G8@H}DaIx_-XzOZHY%t7lSf$Sh6QotM1pu(3OTyRU>a+j=002ovPDHLk FV1iy!ENuV) literal 0 HcmV?d00001 diff --git a/images/menu/4/center.png b/images/menu/4/center.png new file mode 100644 index 0000000000000000000000000000000000000000..45cd3a74327bfc24ce23d127cbfc01116f602a98 GIT binary patch literal 821 zcmeAS@N?(olHy`uVBq!ia0vp^93afd3?%;@)H%Vxz*v~+>>QApoXo&backce~QEa(5;`+d$iTX7pNFYnt=V<((@vgU?|iGi`T_==ii-rRMw zUIdulo-;!#>__pQ`+?7X&E7D(`+x5&*SpsitnsRFFkU<7!-@|-yv~(WM(=R+Ue$eQ z`5{GbE|GnuUn?5t$NGu$o z_)&DKX|ix~iw5H{iKGc}yIzXl_MX8pchlqkAM4)#@Z2P{y3;iBXi_JOXHknw?6fz# zDx6DV)4D>p|KI;ROWJm#Q(3%-);yW#TY0s%E9`%1A>ZCN*`DdWa!iWX$D7PAs)cJe zFJb+Da6e!AbXDDb%+IAS{76_e?U!z4Y9$YIoZo^nu~+LCR_(j6`H|)E?+ezP439nd zPHxNT+W&{dr*@?OetpK(02l`f$sR$z3=CCj3=9n|3=F@3LJcn%7)pV1uM!v-tY$DU zh!@P+6=(yLU<>dGaW&Jm`~UxcT)ey&P=qnb+ueonKa=h~Acwug)7O>#1*@Q#wxxQ6 zS{hJ@+tbA{gyVX0f&(i9g8&2L!lQ}@fx@aKt`Q|Ei6yC4$wjF^iowXh$VAt`RM*fv z#L&{p#MsKzT-(6d%D~`M-uF}#4Y~O#nQ4`{HS9L_zX{Z!2C@N|rmT|l3o45;(=$pK z{PGpx936$y;#7sSqSVx!%H^{@Gy!!e!gQph7AF^F7L;V>=P?uqxjQL%x;mQ~TAG>Z z8tEB^uf63CRICJ3oST?enwFScQd*Q+gsD1vj>u1-YH7IY{FKxjOl7Sp|3JaZ;OXk; Jvd$@?2>`I6IE?@R literal 0 HcmV?d00001 diff --git a/images/menu/4/corner-bottom-left.png b/images/menu/4/corner-bottom-left.png new file mode 100644 index 0000000000000000000000000000000000000000..bd2e12066c10bce8949c44e148e8018fd0c555a7 GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iT~SOJuL0bbnOzo9j4?t{{R19anpqwpd4dKkY6x^!?PP{ zAWo9Ey9>KmV#jMBhrPtp*OmPRtDu;+rFw)KNM6;`#W95Ada^)}QDI_(kfMT;sffpl zrG_1vnwo|NYK)w0j*gBD1s<%LM`o5^0cj|4jVMV;EJ?LWE=mPb3`Pb9W! zm#+Zl=qQvHrz)fsrKaXoE}!+G38+I6rXwY_IJqdZpd>RtkD)lo-ATdI)!EF@(#%ZP zNY5~Q?JakpVkMa3+{C=nw8Z3+(xTKNOx4+QM1BHQOT$&?r=;d!Dr-&o2Z|R4Pgg&e IbxsLQ0EVqd?EnA( literal 0 HcmV?d00001 diff --git a/images/menu/4/corner-bottom-right.png b/images/menu/4/corner-bottom-right.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c70cfc4c990db7643613a110fb4044f4657eca GIT binary patch literal 879 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxB_W2T{{m;`~TZrB_t#gy&b0HIsX6u|HhpE)<8MNk|4ie28U-i z(m`sf3sylfZA zqlCdPUjfe1Q7A1=RY)sJP0guXKI=mhP=_K+M@njOa#3bMNoIZ?LvfJ1lY*zKvzei# znVGJUo?-afTkb%`N-)K_iFu`IiOD6UMX5!Ysa`~<3&hO5p`NzK7j)|&DU6fq2* Lu6{1-oD!MmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2i79!G|F^p)dOMiu+Id*o|Ns9#UzY7WP>!)A$S;_|;n|He z5GTpo-GyB&vEwz6!(QU)>&pIuRZvXZQawTqB(LV_;uyklJvl)@L?k64#LO&Bz=%!g z&@neJ2dAT~9y{8YIzu=Z8NxeQCw{NGy&I@QwZt`|BqgyV)hf9t6-Y4{85o)98kp)D znui!#TA3JInVM@G7+V<_oXY#2ilQMmKP5A*61Rrk#{M@!ZUWf=OpR8_`303lnduoN z41W0vaE^{bX>qDTT2X3hPUZ4hADVzV6k$42Qj3#|G7CyF^Ya*rgWR1IJYAj53@y#f zbdB^3!`I$&2P#&ADb7vID@{vGE-5WaEy7ftJxAmxP_;B%b$&`}4yLl!lz*UzVeoYI Kb6Mw<&;$UlBufPV literal 0 HcmV?d00001 diff --git a/images/menu/4/corner-top-right.png b/images/menu/4/corner-top-right.png new file mode 100644 index 0000000000000000000000000000000000000000..28af2b7ca6d76effd26014289b5a505d2ba90c4d GIT binary patch literal 878 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-ANCfzVxPoX2iT~SOr{p;%dOMiu+Id*o|Ns9#%|W0JD92b5b{qTO1Zq$N*#Jz8R>}DVl|`B986^yU z`3i83jzVd1szO>(YHCj9@>w66fI1XmI#N=LlZ!G7N;32F7>a}3ofJG>oy`m_&CGO- z^bEt--f{;jR)Q(cP0TAzOH3{)ElMrIRGmFXn+a literal 0 HcmV?d00001 diff --git a/images/menu/4/edge-bottom.png b/images/menu/4/edge-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..d13244f59b64bdc9286334749b54d57b3866fe73 GIT binary patch literal 847 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxSHwOC3-td$#eX_-Bm(D;{X5uz1v)LfU=B9-tI1}Kk{E52Xfd; zJbhi+U$6>_Xb{qTO1Zq$N*#Jy!R>}DVl|`B986^yU`3i83jzVd1szO>(YHCj9@>w66fI1Xm zI#N=LlZ!G7N;32F7>a}3ofJG>oy`m_&CGO-^bEt--f{;jR)Q(cP0TAzOH3{)ElMrI kRGmFXmDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxJpP!{NL{CVQFusYxn>Ef7#dTH=O z_7|*zV%nDK5o&2bApuVp#}JO|$q6DMW@!pO3=DQ1%#Q!k%s>f3wZt`|BqgyV)hf9t z6-Y4{85o)98kp)Dnui!#TA3JInVM@G7+V<_oXY#2ilQMmKP5A*61Rrk#{M^f8q`2G z08^M%a(+Q&QD%BZ34>q00-U3xP+FX-kXDqMnp3%a)`upb4n>%bl+@znqRfJl%=|ot z;vjb?1y5IJGeb)=GhHJ+!|=7Y+<}UfV2X1S^GeealS@jAQj0KEXU`G&2~;f&SDl}d XnuDpVHRT^Duo*mE{an^LB{Ts56gNF@ literal 0 HcmV?d00001 diff --git a/images/menu/4/edge-right.png b/images/menu/4/edge-right.png new file mode 100644 index 0000000000000000000000000000000000000000..dd5fa12e91e6eb6b6d00e195127fab95c8f791fc GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w=$TU@XjZb`Ho)PG(@JxHWa+d2N?K zk>mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A@CW#WxSHwOd05*2-|i|QA@TqJ|KioNa)45dN#5=*Ed3cb1A!d&5>H=O z_7|*zV%nDK5o&2bApuVp#}JO|$q5M|L1_v;3=EnFm<)f{-~IrUQ!R0gC`m~yNwrEY zN(E93Mg~SEx(24YhUOuLmR2UlR;K3K2F6wf2B-4Ar=n=c%}>cptHiBgx3T|CpawON z4Zsv;m7HHtS(KTcQNrMtuK?%hD3lhbDx?*qrsh;GpY@>$s6!E^BPF#sxhS)sBr`vc zp*YChNx{?A+04+=%uLrv&oF%LEq9<|C79ye#Jtk9#N?9FqSPWx)!B1IegaiX!&T>} Xq~>5MYfbqF3Ty^XS3j3^P6mDh9TL4sj)9ZgdL<3La&+A4M8zI!?l;Sy_dV^(pNhTalX9l6U3BEwde(Zz=+w0$ z6DMso-I!Q)&Nx^(_2IpDmh*q_{XXZMt+>u{lI6xW^b6?{l9mX>)mS$)_7Go7_Xi4Va10ZUgt_GqjxxZuj)Ru z{E(tIm&m@-uN95+WBo*aTu$}w752ZhkZ45dK1R|yOZRx=nF z#0%!^3bX-A2nG0rxJpP!{NL_6CC@R@+rdoN?*IS)7hWxM2FfxfdAqx?{>XoM9LQlW z@$_|Nf59p!rfsPnp_T>|lJazM4B@z*oWQ{7sL&wbk{nt(bK zVLDP$i<65o3raHc^B9VQ+?^CWU7gJgEzQhyjr0t|*WPjmDprCi&P~iKO-oEJDJ@DZ l!c?6-N8~3^wKQCHeoAT%rn1(Qf1r?O@O1TaS?83{1OUHaLM;FQ literal 0 HcmV?d00001 diff --git a/images/menu/4/original.png b/images/menu/4/original.png new file mode 100644 index 0000000000000000000000000000000000000000..5be8161ca8b079c2a8bc6b9a40735fe9f55d1560 GIT binary patch literal 659 zcmV;E0&M+>P)n+HZ7F0pjwzguZ><` zf!gI>C8TZ8Rw#(t^jg$kP}`t&5EMlaty>qhskoi1ff9L!Gv}M%%sI@Q0c$v|Wb`^O zWU@Ie6!g0m7MEQ17i@Ilq=UYQqN_7=6JcuF$2}G^-g?Yhwa@))O|iJHfTclrOi{I* z@TBncdQLTYN4QN%MPkBd!u^_DQ25T&qh)?EIa%f}leKUt0M-^^SF(zuRjj16jIg{M zcP5=ze(z(x#1YTV&q?eS??fj=5I-)a7$?9mgN({Nj0YbBvZ6-5x0FB2n&c`ns}#^! zB}s}L{i5cjdR$^c^tg;P1+)Ku`>H2~eC6s6Kh!@P##;~Ax8b{J7@tRm@qG-oC%DX3 z^4AVw002ovPDHLkV1gwbBJcnJ literal 0 HcmV?d00001 diff --git a/images/menu/5/center.png b/images/menu/5/center.png new file mode 100755 index 0000000000000000000000000000000000000000..a6950c9f8be0a13ab0a5863308cc8033ea40c037 GIT binary patch literal 807 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;g+ipAn!`URp+Oq=3pvoP5B23PzFy|KbLh*2~7Z|6gU9@ literal 0 HcmV?d00001 diff --git a/images/menu/5/corner-bottom-left.png b/images/menu/5/corner-bottom-left.png new file mode 100755 index 0000000000000000000000000000000000000000..0379ed2cc05b07b5216d2b3b640a34664db81610 GIT binary patch literal 820 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;k{nt(bKVLDP$i<65o3raHc^B9VQ+?^CWU7gJgEzQhy zjr0t|*WPjmDprCi&P~iKO-oEJDJ@DZ!c?6-N8~3^wKQCHeoAT%rn1(Qf1uE1@O1Ta JS?83{1ORUQI_v-d literal 0 HcmV?d00001 diff --git a/images/menu/5/corner-bottom-right.png b/images/menu/5/corner-bottom-right.png new file mode 100755 index 0000000000000000000000000000000000000000..bdd3e590ae857c45fc0f473d607c7ffdbc9e416c GIT binary patch literal 846 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&ml?3?(Gcc4*K5GHuC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;k{nt(bKVLDP$ zi<65o3raHc^B9VQ+?^CWU7gJgEzQhyjr0t|*WPjmDprCi&P~iKO-oEJDJ@DZ!c?6- hN8~3^wKQCHeoAT%rn1(Qf1q$@@O1TaS?83{1OUH-K~Mky literal 0 HcmV?d00001 diff --git a/images/menu/5/corner-top-left.png b/images/menu/5/corner-top-left.png new file mode 100755 index 0000000000000000000000000000000000000000..e487e3d2e1b503c4b6439abdd3aebc764cddf0fd GIT binary patch literal 845 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&ml?3?(Gcc4*K5GHuC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;q#X1YdthT&^(xdRm|!4&5v=9Q);CYO{Jr50hT&YmOk f6R27mt~x&@H3w5!Ysx=RurqkN`njxgN@xNADkDGZ literal 0 HcmV?d00001 diff --git a/images/menu/5/corner-top-right.png b/images/menu/5/corner-top-right.png new file mode 100755 index 0000000000000000000000000000000000000000..14631e212ce94502d17138504915d9c188e85439 GIT binary patch literal 818 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;>wZt`|BqgyV)hf9t6-Y4{85o)98kp)Dnui!# zTA7$w8JcJt7+V<_%oX@ijiMnpKP5A*61Rpoz7EHM8q`2G027o|a(+Q&QD%BZ34>q0 z0-U3xP+FX-kXDqMnp3%a)`upb4n>%bl+@znqRfJl%=|ot;vjb?1y5IJGeb)=GhHJ+ z!|=7Y+<}UfV2X1S^GeealS@jAQj0KEXU`G&2~;f&SDl}dnuDpVHRT^DY#BUV{an^L HB{Ts52F^NZ literal 0 HcmV?d00001 diff --git a/images/menu/5/edge-bottom.png b/images/menu/5/edge-bottom.png new file mode 100755 index 0000000000000000000000000000000000000000..9e3604a3b945565b48ede79a02fb60386ff98d9f GIT binary patch literal 818 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;EhD~gujfydk%YlkiOI#yLQW8s2t&)pUffR$0fsu)>fvK*cd5EE< zm5GU!p^3JEv6X?rT!A0eC>nC}Q!>*kacg+v>u?;XK@DUBFhN-*=ND8KWu|A8F!<#w zz&Sb!rNyZVX+^22IhD(2eP{yeP=x77Ni9w;$}A|!%+F&e4sv%=@N{)HGqf}_(>2mF z3}1W89jI6drZ_h-uQV+&xumoxwFpyn_8gI)K-JQ4)%hu@Ihe{?Q~rU%mci52&t;uc GLK6Un!#GX= literal 0 HcmV?d00001 diff --git a/images/menu/5/edge-left.png b/images/menu/5/edge-left.png new file mode 100755 index 0000000000000000000000000000000000000000..f279d56c8cdd73148ac900986d77597256a88575 GIT binary patch literal 812 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;TG6cX=bKtq-Pku_Le(P zu@X#iZem_(T4HiZX;Eqsrt0iDB0qturQxdcQ&MvmdKI;Vst0P2)F Ac>n+a literal 0 HcmV?d00001 diff --git a/images/menu/5/edge-right.png b/images/menu/5/edge-right.png new file mode 100755 index 0000000000000000000000000000000000000000..b890d163b3075596f853cf075dd5556991e6e71c GIT binary patch literal 812 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;A&B{c_AS!>EaP^dC^y85}Sb4q9e08j8a ADgXcg literal 0 HcmV?d00001 diff --git a/images/menu/5/edge-top.png b/images/menu/5/edge-top.png new file mode 100755 index 0000000000000000000000000000000000000000..f9737a1166e63ed573ed2f04640c39c43a89aca9 GIT binary patch literal 818 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3};|qEX;Iv4#-SSW?-neHFe^7ZI?ii z#6V5$ZbHl^Lz}Q-RMa?m9?z&ko z0!(kunIRSSqj=B#z-PZ^ZOQpm zkfJx2$iC9A6^-*_{X~9TPWA5OZCdVUG2zF-kMe6&*KXOcXHJ6E)-|H93*#SMHohGE zC_2?NSva{xgYlR|(uBBOFU42d#$b?<+8ZW3DEX&QMnsguRCsKq6A+M8V! z&Ly#FU7_3m@Bf`8Z9CDaEM7!wp3L*Dyjt58_P?}{Z||FI&-7k7CdKRHP39NX!nK>1 zuzo+dpD%s7s_s7K=h7E`B&?eDOSdw$l7~6YZ$X*ZtMv=3_FdTg$nyC21#3=*#~yqq zx8-#0|3l(aJJNr@KI3Wtj01&ak04(LhAK4%hK3dfhF?ITh8GMBr9in?2@DKYGZ+}e z3+C(!v;j&mC3(BMF#K=tKeHdmV=wXab!C6SDk!YOcP;qiD#@PsvQH#I50tufuVm1~rfkzyxKLoL^8`l$oAU!r+&$ z0O#l^loqEdq!p#6=2R}9^`QxGe3`^ILO^e!PC{*%+S)zOxH-y zFnsMTcc5Y=nBv^TywbG9gmG0#!@HRp+Oq=3pvoP5B23TLw>8KbLh* G2~7YIusccs literal 0 HcmV?d00001 diff --git a/images/menu/5/original.png b/images/menu/5/original.png new file mode 100644 index 0000000000000000000000000000000000000000..35ad9c4f22c1cbe26bf129fa4b51c1950977e1ae GIT binary patch literal 629 zcmV-*0*d{KP)n+HZ7F0pjwzguZ><` zf!gI>C8TZ8Rw#(t^jg$kP}`t&5EMlaty>qhskoi1ff9L!Gv}M%%sI@Q0c$v|Wb`^O zWU@Ie6!g0m7MEQ17i@Ilq=UYQqN_7=6JcuF$2}G^-g?Yhwa@))O|iJHfTclrOi{I* z@TBncdQLTYN4QN%MPkBd!u^_DQ25T&qh)?EIa%f}leKUt0M-^^SF(zuRjj16jIg{M zcP5=ze(z(x#1YTV&q?eS??fj=5I-)a7$?9mgN({Nj0YbBvZ6-5x0FB2n&c`ns}#^! zB}s}L{i5cjdR$^c^tg;P1+)Ku`>H2~eC6s6Kh!@P##;~Ax8b{J7@tRm@qG-oC%DX3 z^4AVwK*0BwMAP|M&hhYIa)?t|&gfUp= z)}gx*v?38b3dqs%I*s}Mf&v|s#Takx{mPt%mr_h{BEq!`Z}TIZnZe9UXwJD0jPMY` zG%h0D^JR%^>(0O$R|A&#FR)`LZ~`Y_91sztl=cJ~z9pdHM1)$a^V-L=8{xp~Mg#hr zXmxKKFh1lj4gk*b7v+lszyp10Q5OP>>2]>>>24-o%4*8&255;e[i+o>>>2]|=s<<24-(i+o)%4*8}else for(var c=0;c>>2]=r[c>>>2];return this.sigBytes+=n,this},clamp:function(){var t=this.words,e=this.sigBytes;t[e>>>2]&=4294967295<<32-e%4*8,t.length=h.ceil(e/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(t){for(var e=[],r=0;r>>2]>>>24-n%4*8&255;i.push((o>>>4).toString(16)),i.push((15&o).toString(16))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>3]|=parseInt(t.substr(i,2),16)<<24-i%8*4;return new l.init(r,e/2)}},a=s.Latin1={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>24-n%4*8&255;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>2]|=(255&t.charCodeAt(i))<<24-i%4*8;return new l.init(r,e)}},f=s.Utf8={stringify:function(t){try{return decodeURIComponent(escape(a.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return a.parse(unescape(encodeURIComponent(t)))}},d=n.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new l.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=f.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(t){var e,r=this._data,i=r.words,n=r.sigBytes,o=this.blockSize,s=n/(4*o),c=(s=t?h.ceil(s):h.max((0|s)-this._minBufferSize,0))*o,n=h.min(4*c,n);if(c){for(var a=0;a>>32-e}function j(t,e,r,i){var n,o=this._iv;o?(n=o.slice(0),this._iv=void 0):n=this._prevBlock,i.encryptBlock(n,0);for(var s=0;s>24&255)?(r=t>>8&255,i=255&t,255===(e=t>>16&255)?(e=0,255===r?(r=0,255===i?i=0:++i):++r):++e,t=0,t+=e<<16,t+=r<<8,t+=i):t+=1<<24,t}function N(){for(var t=this._X,e=this._C,r=0;r<8;r++)E[r]=e[r];e[0]=e[0]+1295307597+this._b|0,e[1]=e[1]+3545052371+(e[0]>>>0>>0?1:0)|0,e[2]=e[2]+886263092+(e[1]>>>0>>0?1:0)|0,e[3]=e[3]+1295307597+(e[2]>>>0>>0?1:0)|0,e[4]=e[4]+3545052371+(e[3]>>>0>>0?1:0)|0,e[5]=e[5]+886263092+(e[4]>>>0>>0?1:0)|0,e[6]=e[6]+1295307597+(e[5]>>>0>>0?1:0)|0,e[7]=e[7]+3545052371+(e[6]>>>0>>0?1:0)|0,this._b=e[7]>>>0>>0?1:0;for(r=0;r<8;r++){var i=t[r]+e[r],n=65535&i,o=i>>>16;R[r]=((n*n>>>17)+n*o>>>15)+o*o^((4294901760&i)*i|0)+((65535&i)*i|0)}t[0]=R[0]+(R[7]<<16|R[7]>>>16)+(R[6]<<16|R[6]>>>16)|0,t[1]=R[1]+(R[0]<<8|R[0]>>>24)+R[7]|0,t[2]=R[2]+(R[1]<<16|R[1]>>>16)+(R[0]<<16|R[0]>>>16)|0,t[3]=R[3]+(R[2]<<8|R[2]>>>24)+R[1]|0,t[4]=R[4]+(R[3]<<16|R[3]>>>16)+(R[2]<<16|R[2]>>>16)|0,t[5]=R[5]+(R[4]<<8|R[4]>>>24)+R[3]|0,t[6]=R[6]+(R[5]<<16|R[5]>>>16)+(R[4]<<16|R[4]>>>16)|0,t[7]=R[7]+(R[6]<<8|R[6]>>>24)+R[5]|0}function q(){for(var t=this._X,e=this._C,r=0;r<8;r++)O[r]=e[r];e[0]=e[0]+1295307597+this._b|0,e[1]=e[1]+3545052371+(e[0]>>>0>>0?1:0)|0,e[2]=e[2]+886263092+(e[1]>>>0>>0?1:0)|0,e[3]=e[3]+1295307597+(e[2]>>>0>>0?1:0)|0,e[4]=e[4]+3545052371+(e[3]>>>0>>0?1:0)|0,e[5]=e[5]+886263092+(e[4]>>>0>>0?1:0)|0,e[6]=e[6]+1295307597+(e[5]>>>0>>0?1:0)|0,e[7]=e[7]+3545052371+(e[6]>>>0>>0?1:0)|0,this._b=e[7]>>>0>>0?1:0;for(r=0;r<8;r++){var i=t[r]+e[r],n=65535&i,o=i>>>16;I[r]=((n*n>>>17)+n*o>>>15)+o*o^((4294901760&i)*i|0)+((65535&i)*i|0)}t[0]=I[0]+(I[7]<<16|I[7]>>>16)+(I[6]<<16|I[6]>>>16)|0,t[1]=I[1]+(I[0]<<8|I[0]>>>24)+I[7]|0,t[2]=I[2]+(I[1]<<16|I[1]>>>16)+(I[0]<<16|I[0]>>>16)|0,t[3]=I[3]+(I[2]<<8|I[2]>>>24)+I[1]|0,t[4]=I[4]+(I[3]<<16|I[3]>>>16)+(I[2]<<16|I[2]>>>16)|0,t[5]=I[5]+(I[4]<<8|I[4]>>>24)+I[3]|0,t[6]=I[6]+(I[5]<<16|I[5]>>>16)+(I[4]<<16|I[4]>>>16)|0,t[7]=I[7]+(I[6]<<8|I[6]>>>24)+I[5]|0}return F=(M=U).lib,n=F.Base,o=F.WordArray,(M=M.x64={}).Word=n.extend({init:function(t,e){this.high=t,this.low=e}}),M.WordArray=n.extend({init:function(t,e){t=this.words=t||[],this.sigBytes=null!=e?e:8*t.length},toX32:function(){for(var t=this.words,e=t.length,r=[],i=0;i>>2]|=t[i]<<24-i%4*8;s.call(this,r,e)}else s.apply(this,arguments)}).prototype=P),function(){var t=U,n=t.lib.WordArray,t=t.enc;t.Utf16=t.Utf16BE={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>16-n%4*8&65535;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>1]|=t.charCodeAt(i)<<16-i%2*16;return n.create(r,2*e)}};function s(t){return t<<8&4278255360|t>>>8&16711935}t.Utf16LE={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>16-n%4*8&65535);i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>1]|=s(t.charCodeAt(i)<<16-i%2*16);return n.create(r,2*e)}}}(),a=(w=U).lib.WordArray,w.enc.Base64={stringify:function(t){var e=t.words,r=t.sigBytes,i=this._map;t.clamp();for(var n=[],o=0;o>>2]>>>24-o%4*8&255)<<16|(e[o+1>>>2]>>>24-(o+1)%4*8&255)<<8|e[o+2>>>2]>>>24-(o+2)%4*8&255,c=0;c<4&&o+.75*c>>6*(3-c)&63));var a=i.charAt(64);if(a)for(;n.length%4;)n.push(a);return n.join("")},parse:function(t){var e=t.length,r=this._map;if(!(i=this._reverseMap))for(var i=this._reverseMap=[],n=0;n>>6-o%4*2,c=s|c,i[n>>>2]|=c<<24-n%4*8,n++)}return a.create(i,n)}(t,e,i)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},h=(F=U).lib.WordArray,F.enc.Base64url={stringify:function(t,e=!0){var r=t.words,i=t.sigBytes,n=e?this._safe_map:this._map;t.clamp();for(var o=[],s=0;s>>2]>>>24-s%4*8&255)<<16|(r[s+1>>>2]>>>24-(s+1)%4*8&255)<<8|r[s+2>>>2]>>>24-(s+2)%4*8&255,a=0;a<4&&s+.75*a>>6*(3-a)&63));var h=n.charAt(64);if(h)for(;o.length%4;)o.push(h);return o.join("")},parse:function(t,e=!0){var r=t.length,i=e?this._safe_map:this._map;if(!(n=this._reverseMap))for(var n=this._reverseMap=[],o=0;o>>6-o%4*2,c=s|c,i[n>>>2]|=c<<24-n%4*8,n++)}return h.create(i,n)}(t,r,n)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",_safe_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"},function(a){var t=U,e=t.lib,r=e.WordArray,i=e.Hasher,e=t.algo,A=[];!function(){for(var t=0;t<64;t++)A[t]=4294967296*a.abs(a.sin(t+1))|0}();e=e.MD5=i.extend({_doReset:function(){this._hash=new r.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(t,e){for(var r=0;r<16;r++){var i=e+r,n=t[i];t[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}var o=this._hash.words,s=t[e+0],c=t[e+1],a=t[e+2],h=t[e+3],l=t[e+4],f=t[e+5],d=t[e+6],u=t[e+7],p=t[e+8],_=t[e+9],y=t[e+10],v=t[e+11],g=t[e+12],B=t[e+13],w=t[e+14],k=t[e+15],m=H(m=o[0],b=o[1],x=o[2],S=o[3],s,7,A[0]),S=H(S,m,b,x,c,12,A[1]),x=H(x,S,m,b,a,17,A[2]),b=H(b,x,S,m,h,22,A[3]);m=H(m,b,x,S,l,7,A[4]),S=H(S,m,b,x,f,12,A[5]),x=H(x,S,m,b,d,17,A[6]),b=H(b,x,S,m,u,22,A[7]),m=H(m,b,x,S,p,7,A[8]),S=H(S,m,b,x,_,12,A[9]),x=H(x,S,m,b,y,17,A[10]),b=H(b,x,S,m,v,22,A[11]),m=H(m,b,x,S,g,7,A[12]),S=H(S,m,b,x,B,12,A[13]),x=H(x,S,m,b,w,17,A[14]),m=z(m,b=H(b,x,S,m,k,22,A[15]),x,S,c,5,A[16]),S=z(S,m,b,x,d,9,A[17]),x=z(x,S,m,b,v,14,A[18]),b=z(b,x,S,m,s,20,A[19]),m=z(m,b,x,S,f,5,A[20]),S=z(S,m,b,x,y,9,A[21]),x=z(x,S,m,b,k,14,A[22]),b=z(b,x,S,m,l,20,A[23]),m=z(m,b,x,S,_,5,A[24]),S=z(S,m,b,x,w,9,A[25]),x=z(x,S,m,b,h,14,A[26]),b=z(b,x,S,m,p,20,A[27]),m=z(m,b,x,S,B,5,A[28]),S=z(S,m,b,x,a,9,A[29]),x=z(x,S,m,b,u,14,A[30]),m=C(m,b=z(b,x,S,m,g,20,A[31]),x,S,f,4,A[32]),S=C(S,m,b,x,p,11,A[33]),x=C(x,S,m,b,v,16,A[34]),b=C(b,x,S,m,w,23,A[35]),m=C(m,b,x,S,c,4,A[36]),S=C(S,m,b,x,l,11,A[37]),x=C(x,S,m,b,u,16,A[38]),b=C(b,x,S,m,y,23,A[39]),m=C(m,b,x,S,B,4,A[40]),S=C(S,m,b,x,s,11,A[41]),x=C(x,S,m,b,h,16,A[42]),b=C(b,x,S,m,d,23,A[43]),m=C(m,b,x,S,_,4,A[44]),S=C(S,m,b,x,g,11,A[45]),x=C(x,S,m,b,k,16,A[46]),m=D(m,b=C(b,x,S,m,a,23,A[47]),x,S,s,6,A[48]),S=D(S,m,b,x,u,10,A[49]),x=D(x,S,m,b,w,15,A[50]),b=D(b,x,S,m,f,21,A[51]),m=D(m,b,x,S,g,6,A[52]),S=D(S,m,b,x,h,10,A[53]),x=D(x,S,m,b,y,15,A[54]),b=D(b,x,S,m,c,21,A[55]),m=D(m,b,x,S,p,6,A[56]),S=D(S,m,b,x,k,10,A[57]),x=D(x,S,m,b,d,15,A[58]),b=D(b,x,S,m,B,21,A[59]),m=D(m,b,x,S,l,6,A[60]),S=D(S,m,b,x,v,10,A[61]),x=D(x,S,m,b,a,15,A[62]),b=D(b,x,S,m,_,21,A[63]),o[0]=o[0]+m|0,o[1]=o[1]+b|0,o[2]=o[2]+x|0,o[3]=o[3]+S|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32;var n=a.floor(r/4294967296),r=r;e[15+(64+i>>>9<<4)]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8),e[14+(64+i>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(e.length+1),this._process();for(var e=this._hash,o=e.words,s=0;s<4;s++){var c=o[s];o[s]=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8)}return e},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}});function H(t,e,r,i,n,o,s){s=t+(e&r|~e&i)+n+s;return(s<>>32-o)+e}function z(t,e,r,i,n,o,s){s=t+(e&i|r&~i)+n+s;return(s<>>32-o)+e}function C(t,e,r,i,n,o,s){s=t+(e^r^i)+n+s;return(s<>>32-o)+e}function D(t,e,r,i,n,o,s){s=t+(r^(e|~i))+n+s;return(s<>>32-o)+e}t.MD5=i._createHelper(e),t.HmacMD5=i._createHmacHelper(e)}(Math),P=(M=U).lib,t=P.WordArray,e=P.Hasher,P=M.algo,l=[],P=P.SHA1=e.extend({_doReset:function(){this._hash=new t.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],a=0;a<80;a++){a<16?l[a]=0|t[e+a]:(h=l[a-3]^l[a-8]^l[a-14]^l[a-16],l[a]=h<<1|h>>>31);var h=(i<<5|i>>>27)+c+l[a];h+=a<20?1518500249+(n&o|~n&s):a<40?1859775393+(n^o^s):a<60?(n&o|n&s|o&s)-1894007588:(n^o^s)-899497514,c=s,s=o,o=n<<30|n>>>2,n=i,i=h}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+o|0,r[3]=r[3]+s|0,r[4]=r[4]+c|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=Math.floor(r/4294967296),e[15+(64+i>>>9<<4)]=r,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var t=e.clone.call(this);return t._hash=this._hash.clone(),t}}),M.SHA1=e._createHelper(P),M.HmacSHA1=e._createHmacHelper(P),function(n){var t=U,e=t.lib,r=e.WordArray,i=e.Hasher,e=t.algo,o=[],p=[];!function(){function t(t){return 4294967296*(t-(0|t))|0}for(var e=2,r=0;r<64;)!function(t){for(var e=n.sqrt(t),r=2;r<=e;r++)if(!(t%r))return;return 1}(e)||(r<8&&(o[r]=t(n.pow(e,.5))),p[r]=t(n.pow(e,1/3)),r++),e++}();var _=[],e=e.SHA256=i.extend({_doReset:function(){this._hash=new r.init(o.slice(0))},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],a=r[5],h=r[6],l=r[7],f=0;f<64;f++){f<16?_[f]=0|t[e+f]:(d=_[f-15],u=_[f-2],_[f]=((d<<25|d>>>7)^(d<<14|d>>>18)^d>>>3)+_[f-7]+((u<<15|u>>>17)^(u<<13|u>>>19)^u>>>10)+_[f-16]);var d=i&n^i&o^n&o,u=l+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&a^~c&h)+p[f]+_[f],l=h,h=a,a=c,c=s+u|0,s=o,o=n,n=i,i=u+(((i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22))+d)|0}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+o|0,r[3]=r[3]+s|0,r[4]=r[4]+c|0,r[5]=r[5]+a|0,r[6]=r[6]+h|0,r[7]=r[7]+l|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=n.floor(r/4294967296),e[15+(64+i>>>9<<4)]=r,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}});t.SHA256=i._createHelper(e),t.HmacSHA256=i._createHmacHelper(e)}(Math),r=(w=U).lib.WordArray,F=w.algo,i=F.SHA256,F=F.SHA224=i.extend({_doReset:function(){this._hash=new r.init([3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428])},_doFinalize:function(){var t=i._doFinalize.call(this);return t.sigBytes-=4,t}}),w.SHA224=i._createHelper(F),w.HmacSHA224=i._createHmacHelper(F),function(){var t=U,e=t.lib.Hasher,r=t.x64,i=r.Word,n=r.WordArray,r=t.algo;function o(){return i.create.apply(i,arguments)}var t1=[o(1116352408,3609767458),o(1899447441,602891725),o(3049323471,3964484399),o(3921009573,2173295548),o(961987163,4081628472),o(1508970993,3053834265),o(2453635748,2937671579),o(2870763221,3664609560),o(3624381080,2734883394),o(310598401,1164996542),o(607225278,1323610764),o(1426881987,3590304994),o(1925078388,4068182383),o(2162078206,991336113),o(2614888103,633803317),o(3248222580,3479774868),o(3835390401,2666613458),o(4022224774,944711139),o(264347078,2341262773),o(604807628,2007800933),o(770255983,1495990901),o(1249150122,1856431235),o(1555081692,3175218132),o(1996064986,2198950837),o(2554220882,3999719339),o(2821834349,766784016),o(2952996808,2566594879),o(3210313671,3203337956),o(3336571891,1034457026),o(3584528711,2466948901),o(113926993,3758326383),o(338241895,168717936),o(666307205,1188179964),o(773529912,1546045734),o(1294757372,1522805485),o(1396182291,2643833823),o(1695183700,2343527390),o(1986661051,1014477480),o(2177026350,1206759142),o(2456956037,344077627),o(2730485921,1290863460),o(2820302411,3158454273),o(3259730800,3505952657),o(3345764771,106217008),o(3516065817,3606008344),o(3600352804,1432725776),o(4094571909,1467031594),o(275423344,851169720),o(430227734,3100823752),o(506948616,1363258195),o(659060556,3750685593),o(883997877,3785050280),o(958139571,3318307427),o(1322822218,3812723403),o(1537002063,2003034995),o(1747873779,3602036899),o(1955562222,1575990012),o(2024104815,1125592928),o(2227730452,2716904306),o(2361852424,442776044),o(2428436474,593698344),o(2756734187,3733110249),o(3204031479,2999351573),o(3329325298,3815920427),o(3391569614,3928383900),o(3515267271,566280711),o(3940187606,3454069534),o(4118630271,4000239992),o(116418474,1914138554),o(174292421,2731055270),o(289380356,3203993006),o(460393269,320620315),o(685471733,587496836),o(852142971,1086792851),o(1017036298,365543100),o(1126000580,2618297676),o(1288033470,3409855158),o(1501505948,4234509866),o(1607167915,987167468),o(1816402316,1246189591)],e1=[];!function(){for(var t=0;t<80;t++)e1[t]=o()}();r=r.SHA512=e.extend({_doReset:function(){this._hash=new n.init([new i.init(1779033703,4089235720),new i.init(3144134277,2227873595),new i.init(1013904242,4271175723),new i.init(2773480762,1595750129),new i.init(1359893119,2917565137),new i.init(2600822924,725511199),new i.init(528734635,4215389547),new i.init(1541459225,327033209)])},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],a=r[5],h=r[6],l=r[7],f=i.high,d=i.low,u=n.high,p=n.low,_=o.high,y=o.low,v=s.high,g=s.low,B=c.high,w=c.low,k=a.high,m=a.low,S=h.high,x=h.low,b=l.high,r=l.low,A=f,H=d,z=u,C=p,D=_,E=y,R=v,M=g,F=B,P=w,W=k,O=m,I=S,U=x,K=b,X=r,L=0;L<80;L++){var j,T,N=e1[L];L<16?(T=N.high=0|t[e+2*L],j=N.low=0|t[e+2*L+1]):($=(q=e1[L-15]).high,J=q.low,G=(Q=e1[L-2]).high,V=Q.low,Z=(Y=e1[L-7]).high,q=Y.low,Y=(Q=e1[L-16]).high,T=(T=(($>>>1|J<<31)^($>>>8|J<<24)^$>>>7)+Z+((j=(Z=(J>>>1|$<<31)^(J>>>8|$<<24)^(J>>>7|$<<25))+q)>>>0>>0?1:0))+((G>>>19|V<<13)^(G<<3|V>>>29)^G>>>6)+((j+=J=(V>>>19|G<<13)^(V<<3|G>>>29)^(V>>>6|G<<26))>>>0>>0?1:0),j+=$=Q.low,N.high=T=T+Y+(j>>>0<$>>>0?1:0),N.low=j);var q=F&W^~F&I,Z=P&O^~P&U,V=A&z^A&D^z&D,G=(H>>>28|A<<4)^(H<<30|A>>>2)^(H<<25|A>>>7),J=t1[L],Q=J.high,Y=J.low,$=X+((P>>>14|F<<18)^(P>>>18|F<<14)^(P<<23|F>>>9)),N=K+((F>>>14|P<<18)^(F>>>18|P<<14)^(F<<23|P>>>9))+($>>>0>>0?1:0),J=G+(H&C^H&E^C&E),K=I,X=U,I=W,U=O,W=F,O=P,F=R+(N=(N=(N=N+q+(($=$+Z)>>>0>>0?1:0))+Q+(($=$+Y)>>>0>>0?1:0))+T+(($=$+j)>>>0>>0?1:0))+((P=M+$|0)>>>0>>0?1:0)|0,R=D,M=E,D=z,E=C,z=A,C=H,A=N+(((A>>>28|H<<4)^(A<<30|H>>>2)^(A<<25|H>>>7))+V+(J>>>0>>0?1:0))+((H=$+J|0)>>>0<$>>>0?1:0)|0}d=i.low=d+H,i.high=f+A+(d>>>0>>0?1:0),p=n.low=p+C,n.high=u+z+(p>>>0>>0?1:0),y=o.low=y+E,o.high=_+D+(y>>>0>>0?1:0),g=s.low=g+M,s.high=v+R+(g>>>0>>0?1:0),w=c.low=w+P,c.high=B+F+(w>>>0

>>0?1:0),m=a.low=m+O,a.high=k+W+(m>>>0>>0?1:0),x=h.low=x+U,h.high=S+I+(x>>>0>>0?1:0),r=l.low=r+X,l.high=b+K+(r>>>0>>0?1:0)},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[30+(128+i>>>10<<5)]=Math.floor(r/4294967296),e[31+(128+i>>>10<<5)]=r,t.sigBytes=4*e.length,this._process(),this._hash.toX32()},clone:function(){var t=e.clone.call(this);return t._hash=this._hash.clone(),t},blockSize:32});t.SHA512=e._createHelper(r),t.HmacSHA512=e._createHmacHelper(r)}(),P=(M=U).x64,c=P.Word,f=P.WordArray,P=M.algo,d=P.SHA512,P=P.SHA384=d.extend({_doReset:function(){this._hash=new f.init([new c.init(3418070365,3238371032),new c.init(1654270250,914150663),new c.init(2438529370,812702999),new c.init(355462360,4144912697),new c.init(1731405415,4290775857),new c.init(2394180231,1750603025),new c.init(3675008525,1694076839),new c.init(1203062813,3204075428)])},_doFinalize:function(){var t=d._doFinalize.call(this);return t.sigBytes-=16,t}}),M.SHA384=d._createHelper(P),M.HmacSHA384=d._createHmacHelper(P),function(l){var t=U,e=t.lib,f=e.WordArray,i=e.Hasher,d=t.x64.Word,e=t.algo,A=[],H=[],z=[];!function(){for(var t=1,e=0,r=0;r<24;r++){A[t+5*e]=(r+1)*(r+2)/2%64;var i=(2*t+3*e)%5;t=e%5,e=i}for(t=0;t<5;t++)for(e=0;e<5;e++)H[t+5*e]=e+(2*t+3*e)%5*5;for(var n=1,o=0;o<24;o++){for(var s,c=0,a=0,h=0;h<7;h++)1&n&&((s=(1<>>24)|4278255360&(o<<24|o>>>8);(m=r[n]).high^=s=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),m.low^=o}for(var c=0;c<24;c++){for(var a=0;a<5;a++){for(var h=0,l=0,f=0;f<5;f++)h^=(m=r[a+5*f]).high,l^=m.low;var d=C[a];d.high=h,d.low=l}for(a=0;a<5;a++)for(var u=C[(a+4)%5],p=C[(a+1)%5],_=p.high,p=p.low,h=u.high^(_<<1|p>>>31),l=u.low^(p<<1|_>>>31),f=0;f<5;f++)(m=r[a+5*f]).high^=h,m.low^=l;for(var y=1;y<25;y++){var v=(m=r[y]).high,g=m.low,B=A[y];l=B<32?(h=v<>>32-B,g<>>32-B):(h=g<>>64-B,v<>>64-B);B=C[H[y]];B.high=h,B.low=l}var w=C[0],k=r[0];w.high=k.high,w.low=k.low;for(a=0;a<5;a++)for(f=0;f<5;f++){var m=r[y=a+5*f],S=C[y],x=C[(a+1)%5+5*f],b=C[(a+2)%5+5*f];m.high=S.high^~x.high&b.high,m.low=S.low^~x.low&b.low}m=r[0],k=z[c];m.high^=k.high,m.low^=k.low}},_doFinalize:function(){var t=this._data,e=t.words,r=(this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;e[r>>>5]|=1<<24-r%32,e[(l.ceil((1+r)/i)*i>>>5)-1]|=128,t.sigBytes=4*e.length,this._process();for(var n=this._state,e=this.cfg.outputLength/8,o=e/8,s=[],c=0;c>>24)|4278255360&(h<<24|h>>>8);s.push(a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)),s.push(h)}return new f.init(s,e)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),r=0;r<25;r++)e[r]=e[r].clone();return t}});t.SHA3=i._createHelper(e),t.HmacSHA3=i._createHmacHelper(e)}(Math),Math,F=(w=U).lib,u=F.WordArray,p=F.Hasher,F=w.algo,S=u.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),x=u.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),b=u.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),A=u.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),H=u.create([0,1518500249,1859775393,2400959708,2840853838]),z=u.create([1352829926,1548603684,1836072691,2053994217,0]),F=F.RIPEMD160=p.extend({_doReset:function(){this._hash=u.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,e){for(var r=0;r<16;r++){var i=e+r,n=t[i];t[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}for(var o,s,c,a,h,l,f=this._hash.words,d=H.words,u=z.words,p=S.words,_=x.words,y=b.words,v=A.words,g=o=f[0],B=s=f[1],w=c=f[2],k=a=f[3],m=h=f[4],r=0;r<80;r+=1)l=o+t[e+p[r]]|0,l+=r<16?(s^c^a)+d[0]:r<32?K(s,c,a)+d[1]:r<48?((s|~c)^a)+d[2]:r<64?X(s,c,a)+d[3]:(s^(c|~a))+d[4],l=(l=L(l|=0,y[r]))+h|0,o=h,h=a,a=L(c,10),c=s,s=l,l=g+t[e+_[r]]|0,l+=r<16?(B^(w|~k))+u[0]:r<32?X(B,w,k)+u[1]:r<48?((B|~w)^k)+u[2]:r<64?K(B,w,k)+u[3]:(B^w^k)+u[4],l=(l=L(l|=0,v[r]))+m|0,g=m,m=k,k=L(w,10),w=B,B=l;l=f[1]+c+k|0,f[1]=f[2]+a+m|0,f[2]=f[3]+h+g|0,f[3]=f[4]+o+B|0,f[4]=f[0]+s+w|0,f[0]=l},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(e.length+1),this._process();for(var e=this._hash,n=e.words,o=0;o<5;o++){var s=n[o];n[o]=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8)}return e},clone:function(){var t=p.clone.call(this);return t._hash=this._hash.clone(),t}}),w.RIPEMD160=p._createHelper(F),w.HmacRIPEMD160=p._createHmacHelper(F),P=(M=U).lib.Base,_=M.enc.Utf8,M.algo.HMAC=P.extend({init:function(t,e){t=this._hasher=new t.init,"string"==typeof e&&(e=_.parse(e));var r=t.blockSize,i=4*r;(e=e.sigBytes>i?t.finalize(e):e).clamp();for(var t=this._oKey=e.clone(),e=this._iKey=e.clone(),n=t.words,o=e.words,s=0;s>>2];t.sigBytes-=e}},d=(e.BlockCipher=a.extend({cfg:a.cfg.extend({mode:n,padding:l}),reset:function(){var t;a.reset.call(this);var e=this.cfg,r=e.iv,e=e.mode;this._xformMode==this._ENC_XFORM_MODE?t=e.createEncryptor:(t=e.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==t?this._mode.init(this,r&&r.words):(this._mode=t.call(e,this,r&&r.words),this._mode.__creator=t)},_doProcessBlock:function(t,e){this._mode.processBlock(t,e)},_doFinalize:function(){var t,e=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(e.pad(this._data,this.blockSize),t=this._process(!0)):(t=this._process(!0),e.unpad(t)),t},blockSize:4}),e.CipherParams=r.extend({init:function(t){this.mixIn(t)},toString:function(t){return(t||this.formatter).stringify(this)}})),l=(t.format={}).OpenSSL={stringify:function(t){var e=t.ciphertext,t=t.salt,e=t?s.create([1398893684,1701076831]).concat(t).concat(e):e;return e.toString(o)},parse:function(t){var e,r=o.parse(t),t=r.words;return 1398893684==t[0]&&1701076831==t[1]&&(e=s.create(t.slice(2,4)),t.splice(0,4),r.sigBytes-=16),d.create({ciphertext:r,salt:e})}},u=e.SerializableCipher=r.extend({cfg:r.extend({format:l}),encrypt:function(t,e,r,i){i=this.cfg.extend(i);var n=t.createEncryptor(r,i),e=n.finalize(e),n=n.cfg;return d.create({ciphertext:e,key:r,iv:n.iv,algorithm:t,mode:n.mode,padding:n.padding,blockSize:t.blockSize,formatter:i.format})},decrypt:function(t,e,r,i){return i=this.cfg.extend(i),e=this._parse(e,i.format),t.createDecryptor(r,i).finalize(e.ciphertext)},_parse:function(t,e){return"string"==typeof t?e.parse(t,this):t}}),t=(t.kdf={}).OpenSSL={execute:function(t,e,r,i){i=i||s.random(8);t=c.create({keySize:e+r}).compute(t,i),r=s.create(t.words.slice(e),4*r);return t.sigBytes=4*e,d.create({key:t,iv:r,salt:i})}},p=e.PasswordBasedCipher=u.extend({cfg:u.cfg.extend({kdf:t}),encrypt:function(t,e,r,i){r=(i=this.cfg.extend(i)).kdf.execute(r,t.keySize,t.ivSize);i.iv=r.iv;i=u.encrypt.call(this,t,e,r.key,i);return i.mixIn(r),i},decrypt:function(t,e,r,i){i=this.cfg.extend(i),e=this._parse(e,i.format);r=i.kdf.execute(r,t.keySize,t.ivSize,e.salt);return i.iv=r.iv,u.decrypt.call(this,t,e,r.key,i)}})}(),U.mode.CFB=((F=U.lib.BlockCipherMode.extend()).Encryptor=F.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize;j.call(this,t,e,i,r),this._prevBlock=t.slice(e,e+i)}}),F.Decryptor=F.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=t.slice(e,e+i);j.call(this,t,e,i,r),this._prevBlock=n}}),F),U.mode.CTR=(M=U.lib.BlockCipherMode.extend(),P=M.Encryptor=M.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=this._iv,o=this._counter;n&&(o=this._counter=n.slice(0),this._iv=void 0);var s=o.slice(0);r.encryptBlock(s,0),o[i-1]=o[i-1]+1|0;for(var c=0;c>>2]|=e<<24-r%4*8,t.sigBytes+=e},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},U.pad.Iso10126={pad:function(t,e){e*=4,e-=t.sigBytes%e;t.concat(U.lib.WordArray.random(e-1)).concat(U.lib.WordArray.create([e<<24],1))},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},U.pad.Iso97971={pad:function(t,e){t.concat(U.lib.WordArray.create([2147483648],1)),U.pad.ZeroPadding.pad(t,e)},unpad:function(t){U.pad.ZeroPadding.unpad(t),t.sigBytes--}},U.pad.ZeroPadding={pad:function(t,e){e*=4;t.clamp(),t.sigBytes+=e-(t.sigBytes%e||e)},unpad:function(t){for(var e=t.words,r=t.sigBytes-1,r=t.sigBytes-1;0<=r;r--)if(e[r>>>2]>>>24-r%4*8&255){t.sigBytes=r+1;break}}},U.pad.NoPadding={pad:function(){},unpad:function(){}},m=(P=U).lib.CipherParams,C=P.enc.Hex,P.format.Hex={stringify:function(t){return t.ciphertext.toString(C)},parse:function(t){t=C.parse(t);return m.create({ciphertext:t})}},function(){var t=U,e=t.lib.BlockCipher,r=t.algo,h=[],l=[],f=[],d=[],u=[],p=[],_=[],y=[],v=[],g=[];!function(){for(var t=[],e=0;e<256;e++)t[e]=e<128?e<<1:e<<1^283;for(var r=0,i=0,e=0;e<256;e++){var n=i^i<<1^i<<2^i<<3^i<<4;h[r]=n=n>>>8^255&n^99;var o=t[l[n]=r],s=t[o],c=t[s],a=257*t[n]^16843008*n;f[r]=a<<24|a>>>8,d[r]=a<<16|a>>>16,u[r]=a<<8|a>>>24,p[r]=a,_[n]=(a=16843009*c^65537*s^257*o^16843008*r)<<24|a>>>8,y[n]=a<<16|a>>>16,v[n]=a<<8|a>>>24,g[n]=a,r?(r=o^t[t[t[c^o]]],i^=t[t[i]]):r=i=1}}();var B=[0,1,2,4,8,16,32,64,128,27,54],r=r.AES=e.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var t=this._keyPriorReset=this._key,e=t.words,r=t.sigBytes/4,i=4*(1+(this._nRounds=6+r)),n=this._keySchedule=[],o=0;o>>24]<<24|h[a>>>16&255]<<16|h[a>>>8&255]<<8|h[255&a]):(a=h[(a=a<<8|a>>>24)>>>24]<<24|h[a>>>16&255]<<16|h[a>>>8&255]<<8|h[255&a],a^=B[o/r|0]<<24),n[o]=n[o-r]^a);for(var s=this._invKeySchedule=[],c=0;c>>24]]^y[h[a>>>16&255]]^v[h[a>>>8&255]]^g[h[255&a]]}}},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._keySchedule,f,d,u,p,h)},decryptBlock:function(t,e){var r=t[e+1];t[e+1]=t[e+3],t[e+3]=r,this._doCryptBlock(t,e,this._invKeySchedule,_,y,v,g,l);r=t[e+1];t[e+1]=t[e+3],t[e+3]=r},_doCryptBlock:function(t,e,r,i,n,o,s,c){for(var a=this._nRounds,h=t[e]^r[0],l=t[e+1]^r[1],f=t[e+2]^r[2],d=t[e+3]^r[3],u=4,p=1;p>>24]^n[l>>>16&255]^o[f>>>8&255]^s[255&d]^r[u++],y=i[l>>>24]^n[f>>>16&255]^o[d>>>8&255]^s[255&h]^r[u++],v=i[f>>>24]^n[d>>>16&255]^o[h>>>8&255]^s[255&l]^r[u++],g=i[d>>>24]^n[h>>>16&255]^o[l>>>8&255]^s[255&f]^r[u++],h=_,l=y,f=v,d=g;_=(c[h>>>24]<<24|c[l>>>16&255]<<16|c[f>>>8&255]<<8|c[255&d])^r[u++],y=(c[l>>>24]<<24|c[f>>>16&255]<<16|c[d>>>8&255]<<8|c[255&h])^r[u++],v=(c[f>>>24]<<24|c[d>>>16&255]<<16|c[h>>>8&255]<<8|c[255&l])^r[u++],g=(c[d>>>24]<<24|c[h>>>16&255]<<16|c[l>>>8&255]<<8|c[255&f])^r[u++];t[e]=_,t[e+1]=y,t[e+2]=v,t[e+3]=g},keySize:8});t.AES=e._createHelper(r)}(),function(){var t=U,e=t.lib,i=e.WordArray,r=e.BlockCipher,e=t.algo,h=[57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4],l=[14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32],f=[1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28],d=[{0:8421888,268435456:32768,536870912:8421378,805306368:2,1073741824:512,1342177280:8421890,1610612736:8389122,1879048192:8388608,2147483648:514,2415919104:8389120,2684354560:33280,2952790016:8421376,3221225472:32770,3489660928:8388610,3758096384:0,4026531840:33282,134217728:0,402653184:8421890,671088640:33282,939524096:32768,1207959552:8421888,1476395008:512,1744830464:8421378,2013265920:2,2281701376:8389120,2550136832:33280,2818572288:8421376,3087007744:8389122,3355443200:8388610,3623878656:32770,3892314112:514,4160749568:8388608,1:32768,268435457:2,536870913:8421888,805306369:8388608,1073741825:8421378,1342177281:33280,1610612737:512,1879048193:8389122,2147483649:8421890,2415919105:8421376,2684354561:8388610,2952790017:33282,3221225473:514,3489660929:8389120,3758096385:32770,4026531841:0,134217729:8421890,402653185:8421376,671088641:8388608,939524097:512,1207959553:32768,1476395009:8388610,1744830465:2,2013265921:33282,2281701377:32770,2550136833:8389122,2818572289:514,3087007745:8421888,3355443201:8389120,3623878657:0,3892314113:33280,4160749569:8421378},{0:1074282512,16777216:16384,33554432:524288,50331648:1074266128,67108864:1073741840,83886080:1074282496,100663296:1073758208,117440512:16,134217728:540672,150994944:1073758224,167772160:1073741824,184549376:540688,201326592:524304,218103808:0,234881024:16400,251658240:1074266112,8388608:1073758208,25165824:540688,41943040:16,58720256:1073758224,75497472:1074282512,92274688:1073741824,109051904:524288,125829120:1074266128,142606336:524304,159383552:0,176160768:16384,192937984:1074266112,209715200:1073741840,226492416:540672,243269632:1074282496,260046848:16400,268435456:0,285212672:1074266128,301989888:1073758224,318767104:1074282496,335544320:1074266112,352321536:16,369098752:540688,385875968:16384,402653184:16400,419430400:524288,436207616:524304,452984832:1073741840,469762048:540672,486539264:1073758208,503316480:1073741824,520093696:1074282512,276824064:540688,293601280:524288,310378496:1074266112,327155712:16384,343932928:1073758208,360710144:1074282512,377487360:16,394264576:1073741824,411041792:1074282496,427819008:1073741840,444596224:1073758224,461373440:524304,478150656:0,494927872:16400,511705088:1074266128,528482304:540672},{0:260,1048576:0,2097152:67109120,3145728:65796,4194304:65540,5242880:67108868,6291456:67174660,7340032:67174400,8388608:67108864,9437184:67174656,10485760:65792,11534336:67174404,12582912:67109124,13631488:65536,14680064:4,15728640:256,524288:67174656,1572864:67174404,2621440:0,3670016:67109120,4718592:67108868,5767168:65536,6815744:65540,7864320:260,8912896:4,9961472:256,11010048:67174400,12058624:65796,13107200:65792,14155776:67109124,15204352:67174660,16252928:67108864,16777216:67174656,17825792:65540,18874368:65536,19922944:67109120,20971520:256,22020096:67174660,23068672:67108868,24117248:0,25165824:67109124,26214400:67108864,27262976:4,28311552:65792,29360128:67174400,30408704:260,31457280:65796,32505856:67174404,17301504:67108864,18350080:260,19398656:67174656,20447232:0,21495808:65540,22544384:67109120,23592960:256,24641536:67174404,25690112:65536,26738688:67174660,27787264:65796,28835840:67108868,29884416:67109124,30932992:67174400,31981568:4,33030144:65792},{0:2151682048,65536:2147487808,131072:4198464,196608:2151677952,262144:0,327680:4198400,393216:2147483712,458752:4194368,524288:2147483648,589824:4194304,655360:64,720896:2147487744,786432:2151678016,851968:4160,917504:4096,983040:2151682112,32768:2147487808,98304:64,163840:2151678016,229376:2147487744,294912:4198400,360448:2151682112,425984:0,491520:2151677952,557056:4096,622592:2151682048,688128:4194304,753664:4160,819200:2147483648,884736:4194368,950272:4198464,1015808:2147483712,1048576:4194368,1114112:4198400,1179648:2147483712,1245184:0,1310720:4160,1376256:2151678016,1441792:2151682048,1507328:2147487808,1572864:2151682112,1638400:2147483648,1703936:2151677952,1769472:4198464,1835008:2147487744,1900544:4194304,1966080:64,2031616:4096,1081344:2151677952,1146880:2151682112,1212416:0,1277952:4198400,1343488:4194368,1409024:2147483648,1474560:2147487808,1540096:64,1605632:2147483712,1671168:4096,1736704:2147487744,1802240:2151678016,1867776:4160,1933312:2151682048,1998848:4194304,2064384:4198464},{0:128,4096:17039360,8192:262144,12288:536870912,16384:537133184,20480:16777344,24576:553648256,28672:262272,32768:16777216,36864:537133056,40960:536871040,45056:553910400,49152:553910272,53248:0,57344:17039488,61440:553648128,2048:17039488,6144:553648256,10240:128,14336:17039360,18432:262144,22528:537133184,26624:553910272,30720:536870912,34816:537133056,38912:0,43008:553910400,47104:16777344,51200:536871040,55296:553648128,59392:16777216,63488:262272,65536:262144,69632:128,73728:536870912,77824:553648256,81920:16777344,86016:553910272,90112:537133184,94208:16777216,98304:553910400,102400:553648128,106496:17039360,110592:537133056,114688:262272,118784:536871040,122880:0,126976:17039488,67584:553648256,71680:16777216,75776:17039360,79872:537133184,83968:536870912,88064:17039488,92160:128,96256:553910272,100352:262272,104448:553910400,108544:0,112640:553648128,116736:16777344,120832:262144,124928:537133056,129024:536871040},{0:268435464,256:8192,512:270532608,768:270540808,1024:268443648,1280:2097152,1536:2097160,1792:268435456,2048:0,2304:268443656,2560:2105344,2816:8,3072:270532616,3328:2105352,3584:8200,3840:270540800,128:270532608,384:270540808,640:8,896:2097152,1152:2105352,1408:268435464,1664:268443648,1920:8200,2176:2097160,2432:8192,2688:268443656,2944:270532616,3200:0,3456:270540800,3712:2105344,3968:268435456,4096:268443648,4352:270532616,4608:270540808,4864:8200,5120:2097152,5376:268435456,5632:268435464,5888:2105344,6144:2105352,6400:0,6656:8,6912:270532608,7168:8192,7424:268443656,7680:270540800,7936:2097160,4224:8,4480:2105344,4736:2097152,4992:268435464,5248:268443648,5504:8200,5760:270540808,6016:270532608,6272:270540800,6528:270532616,6784:8192,7040:2105352,7296:2097160,7552:0,7808:268435456,8064:268443656},{0:1048576,16:33555457,32:1024,48:1049601,64:34604033,80:0,96:1,112:34603009,128:33555456,144:1048577,160:33554433,176:34604032,192:34603008,208:1025,224:1049600,240:33554432,8:34603009,24:0,40:33555457,56:34604032,72:1048576,88:33554433,104:33554432,120:1025,136:1049601,152:33555456,168:34603008,184:1048577,200:1024,216:34604033,232:1,248:1049600,256:33554432,272:1048576,288:33555457,304:34603009,320:1048577,336:33555456,352:34604032,368:1049601,384:1025,400:34604033,416:1049600,432:1,448:0,464:34603008,480:33554433,496:1024,264:1049600,280:33555457,296:34603009,312:1,328:33554432,344:1048576,360:1025,376:34604032,392:33554433,408:34603008,424:0,440:34604033,456:1049601,472:1024,488:33555456,504:1048577},{0:134219808,1:131072,2:134217728,3:32,4:131104,5:134350880,6:134350848,7:2048,8:134348800,9:134219776,10:133120,11:134348832,12:2080,13:0,14:134217760,15:133152,2147483648:2048,2147483649:134350880,2147483650:134219808,2147483651:134217728,2147483652:134348800,2147483653:133120,2147483654:133152,2147483655:32,2147483656:134217760,2147483657:2080,2147483658:131104,2147483659:134350848,2147483660:0,2147483661:134348832,2147483662:134219776,2147483663:131072,16:133152,17:134350848,18:32,19:2048,20:134219776,21:134217760,22:134348832,23:131072,24:0,25:131104,26:134348800,27:134219808,28:134350880,29:133120,30:2080,31:134217728,2147483664:131072,2147483665:2048,2147483666:134348832,2147483667:133152,2147483668:32,2147483669:134348800,2147483670:134217728,2147483671:134219808,2147483672:134350880,2147483673:134217760,2147483674:134219776,2147483675:0,2147483676:133120,2147483677:2080,2147483678:131104,2147483679:134350848}],u=[4160749569,528482304,33030144,2064384,129024,8064,504,2147483679],n=e.DES=r.extend({_doReset:function(){for(var t=this._key.words,e=[],r=0;r<56;r++){var i=h[r]-1;e[r]=t[i>>>5]>>>31-i%32&1}for(var n=this._subKeys=[],o=0;o<16;o++){for(var s=n[o]=[],c=f[o],r=0;r<24;r++)s[r/6|0]|=e[(l[r]-1+c)%28]<<31-r%6,s[4+(r/6|0)]|=e[28+(l[r+24]-1+c)%28]<<31-r%6;s[0]=s[0]<<1|s[0]>>>31;for(r=1;r<7;r++)s[r]=s[r]>>>4*(r-1)+3;s[7]=s[7]<<5|s[7]>>>27}for(var a=this._invSubKeys=[],r=0;r<16;r++)a[r]=n[15-r]},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._subKeys)},decryptBlock:function(t,e){this._doCryptBlock(t,e,this._invSubKeys)},_doCryptBlock:function(t,e,r){this._lBlock=t[e],this._rBlock=t[e+1],p.call(this,4,252645135),p.call(this,16,65535),_.call(this,2,858993459),_.call(this,8,16711935),p.call(this,1,1431655765);for(var i=0;i<16;i++){for(var n=r[i],o=this._lBlock,s=this._rBlock,c=0,a=0;a<8;a++)c|=d[a][((s^n[a])&u[a])>>>0];this._lBlock=s,this._rBlock=o^c}var h=this._lBlock;this._lBlock=this._rBlock,this._rBlock=h,p.call(this,1,1431655765),_.call(this,8,16711935),_.call(this,2,858993459),p.call(this,16,65535),p.call(this,4,252645135),t[e]=this._lBlock,t[e+1]=this._rBlock},keySize:2,ivSize:2,blockSize:2});function p(t,e){e=(this._lBlock>>>t^this._rBlock)&e;this._rBlock^=e,this._lBlock^=e<>>t^this._lBlock)&e;this._lBlock^=e,this._rBlock^=e<192.");var e=t.slice(0,2),r=t.length<4?t.slice(0,2):t.slice(2,4),t=t.length<6?t.slice(0,2):t.slice(4,6);this._des1=n.createEncryptor(i.create(e)),this._des2=n.createEncryptor(i.create(r)),this._des3=n.createEncryptor(i.create(t))},encryptBlock:function(t,e){this._des1.encryptBlock(t,e),this._des2.decryptBlock(t,e),this._des3.encryptBlock(t,e)},decryptBlock:function(t,e){this._des3.decryptBlock(t,e),this._des2.encryptBlock(t,e),this._des1.decryptBlock(t,e)},keySize:6,ivSize:2,blockSize:2});t.TripleDES=r._createHelper(e)}(),function(){var t=U,e=t.lib.StreamCipher,r=t.algo,i=r.RC4=e.extend({_doReset:function(){for(var t=this._key,e=t.words,r=t.sigBytes,i=this._S=[],n=0;n<256;n++)i[n]=n;for(var n=0,o=0;n<256;n++){var s=n%r,s=e[s>>>2]>>>24-s%4*8&255,o=(o+i[n]+s)%256,s=i[n];i[n]=i[o],i[o]=s}this._i=this._j=0},_doProcessBlock:function(t,e){t[e]^=n.call(this)},keySize:8,ivSize:0});function n(){for(var t=this._S,e=this._i,r=this._j,i=0,n=0;n<4;n++){var r=(r+t[e=(e+1)%256])%256,o=t[e];t[e]=t[r],t[r]=o,i|=t[(t[e]+t[r])%256]<<24-8*n}return this._i=e,this._j=r,i}t.RC4=e._createHelper(i);r=r.RC4Drop=i.extend({cfg:i.cfg.extend({drop:192}),_doReset:function(){i._doReset.call(this);for(var t=this.cfg.drop;0>>24)|4278255360&(t[r]<<24|t[r]>>>8);for(var i=this._X=[t[0],t[3]<<16|t[2]>>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],n=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]],r=this._b=0;r<4;r++)N.call(this);for(r=0;r<8;r++)n[r]^=i[r+4&7];if(e){var o=e.words,s=o[0],c=o[1],e=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),o=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),s=e>>>16|4294901760&o,c=o<<16|65535&e;n[0]^=e,n[1]^=s,n[2]^=o,n[3]^=c,n[4]^=e,n[5]^=s,n[6]^=o,n[7]^=c;for(r=0;r<4;r++)N.call(this)}},_doProcessBlock:function(t,e){var r=this._X;N.call(this),D[0]=r[0]^r[5]>>>16^r[3]<<16,D[1]=r[2]^r[7]>>>16^r[5]<<16,D[2]=r[4]^r[1]>>>16^r[7]<<16,D[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)D[i]=16711935&(D[i]<<8|D[i]>>>24)|4278255360&(D[i]<<24|D[i]>>>8),t[e+i]^=D[i]},blockSize:4,ivSize:2}),M.Rabbit=F._createHelper(P),F=(M=U).lib.StreamCipher,P=M.algo,W=[],O=[],I=[],P=P.RabbitLegacy=F.extend({_doReset:function(){for(var t=this._key.words,e=this.cfg.iv,r=this._X=[t[0],t[3]<<16|t[2]>>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],i=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]],n=this._b=0;n<4;n++)q.call(this);for(n=0;n<8;n++)i[n]^=r[n+4&7];if(e){var o=e.words,s=o[0],t=o[1],e=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),o=16711935&(t<<8|t>>>24)|4278255360&(t<<24|t>>>8),s=e>>>16|4294901760&o,t=o<<16|65535&e;i[0]^=e,i[1]^=s,i[2]^=o,i[3]^=t,i[4]^=e,i[5]^=s,i[6]^=o,i[7]^=t;for(n=0;n<4;n++)q.call(this)}},_doProcessBlock:function(t,e){var r=this._X;q.call(this),W[0]=r[0]^r[5]>>>16^r[3]<<16,W[1]=r[2]^r[7]>>>16^r[5]<<16,W[2]=r[4]^r[1]>>>16^r[7]<<16,W[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)W[i]=16711935&(W[i]<<8|W[i]>>>24)|4278255360&(W[i]<<24|W[i]>>>8),t[e+i]^=W[i]},blockSize:4,ivSize:2}),M.RabbitLegacy=F._createHelper(P),U}); \ No newline at end of file diff --git a/manifest_chrome.json b/manifest_chrome.json deleted file mode 100644 index 7d8ee96..0000000 --- a/manifest_chrome.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "manifest_version": 3, - "name": "Rogue Dex", - "version": "2.6", - "permissions": ["activeTab", "webRequest"], - "host_permissions": [ - "https://pokerogue.net/*", - "https://api.pokerogue.net/*" - ], - "background": { - "service_worker": "background.js" - }, - "content_scripts": [ - { - "matches": ["https://api.pokerogue.net/*", "https://pokerogue.net/*"], - "js": ["inject.js"], - "run_at": "document_start", - "all_frames": true - }, - { - "matches": ["https://pokerogue.net/*"], - "js": ["content.js", "libs/crypto-js.min.js"], - "css": ["styles.css"] - } - ], - "web_accessible_resources": [ - { - "resources": ["inject.js", "injected.js"], - "matches": [""], - "extension_ids": [] - } - ] -} diff --git a/options/generateSettingsUI.js b/options/generateSettingsUI.js new file mode 100644 index 0000000..19c3b05 --- /dev/null +++ b/options/generateSettingsUI.js @@ -0,0 +1,45 @@ +import settingsTemplate from './settingsTemplate.js'; + +const generateSettingsUI = () => { + const container = document.getElementById('input-container'); + + for (const key in settingsTemplate) { + const setting = settingsTemplate[key]; + const inputItem = document.createElement('div'); + inputItem.classList.add('input-item'); + + const label = document.createElement('label'); + label.classList.add('setting-label'); + label.textContent = setting.text; + + const settingOptions = document.createElement('span'); + settingOptions.classList.add('setting-options'); + + setting.options.forEach(option => { + const span = document.createElement('span'); + span.classList.add('option'); + let appended = ""; + if(setting.hasOwnProperty("appendText")){ + appended = setting.appendText; + } + span.textContent = option+appended; + span.setAttribute('data-setting', setting.localStorage); + span.setAttribute('data-value', option); + + if (setting.type === 'Bool') { + span.setAttribute('data-value', option === "Yes" ? "true" : "false"); + label.classList.add('bool-label'); + } else if (setting.type === 'Float' || setting.type === 'Int') { + span.setAttribute('data-value', option); + } + + settingOptions.appendChild(span); + }); + + inputItem.appendChild(label); + inputItem.appendChild(settingOptions); + container.appendChild(inputItem); + } +}; + +export default generateSettingsUI; diff --git a/options/imageInjector.js b/options/imageInjector.js new file mode 100644 index 0000000..367fcd2 --- /dev/null +++ b/options/imageInjector.js @@ -0,0 +1,54 @@ +export default class ImageInjector { + constructor() { + this.browserApi = typeof browser !== "undefined" ? browser : chrome; + this.extensionId = this.browserApi.runtime.id; + this.preloadedImages = {}; + this.preloadImages(); + } + + preloadImages() { + for (let menuType = 1; menuType <= 5; menuType++) { + this.preloadedImages[menuType] = {}; + const parts = [ + 'corner-top-left', + 'corner-top-right', + 'corner-bottom-left', + 'corner-bottom-right', + 'edge-top', + 'edge-bottom', + 'edge-left', + 'edge-right', + 'center' + ]; + + parts.forEach(part => { + const img = new Image(); + const url = `chrome-extension://${this.extensionId}/images/menu/${menuType}/${part}.png`; + img.src = url; + this.preloadedImages[menuType][part] = img; + }); + } + } + + injectImages(menuType = 1) { + const parts = [ + { class: 'corner-top-left', part: 'corner-top-left' }, + { class: 'corner-top-right', part: 'corner-top-right' }, + { class: 'corner-bottom-left', part: 'corner-bottom-left' }, + { class: 'corner-bottom-right', part: 'corner-bottom-right' }, + { class: 'edge-top', part: 'edge-top' }, + { class: 'edge-bottom', part: 'edge-bottom' }, + { class: 'edge-left', part: 'edge-left' }, + { class: 'edge-right', part: 'edge-right' }, + { class: 'center', part: 'center' }, + ]; + + parts.forEach(part => { + const element = document.querySelector(`.${part.class}`); + if (element) { + const img = this.preloadedImages[menuType][part.part]; + element.style.backgroundImage = `url('${img.src}')`; + } + }); + } +} diff --git a/options/options.css b/options/options.css new file mode 100644 index 0000000..9355479 --- /dev/null +++ b/options/options.css @@ -0,0 +1,207 @@ +@font-face { + font-family: 'PKMNems'; + src: url('../fonts/pkmnems.ttf') format('truetype'); +} + +:root { + --corner-size: 32px; /* Adjust this value as needed */ + --red-main: rgb(248, 136, 128); + --red-sub: rgb(248, 48, 24); + --yellow-main: rgb(248, 176, 90); + --yellow-sub: rgb(192, 120, 0); + --white-main: rgb(248, 248, 248); + --white-sub: rgb(107, 90, 115); + --setting-text-size: 30px; +} + +body { + margin: 0; + position: relative; + width: 700px; /* Defined width */ + /*height: 300px; !* Defined height *!*/ + overflow: hidden; + background: rgb(55, 45, 62); /* Make the background transparent */ + background-size: cover; + background-repeat: no-repeat; +} + +.background-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; /* Ensure it doesn't block other content */ + pointer-events: none; /* Ensure it doesn't interact with other elements */ + background: transparent; /* Ensure the container background is transparent */ +} + +.background-container > div { + position: absolute; + background-size: contain; + image-rendering: pixelated; + background-color: transparent; /* Ensure each part is transparent */ +} + +.corner-top-left, +.corner-top-right, +.corner-bottom-left, +.corner-bottom-right { + width: var(--corner-size); + height: var(--corner-size); + background-repeat: no-repeat; + image-rendering: pixelated; + background-color: transparent; /* Ensure corners are transparent */ +} + +.corner-top-left { + top: 0; + left: 0; +} + +.corner-top-right { + top: 0; + right: 0; +} + +.corner-bottom-left { + bottom: 0; + left: 0; +} + +.corner-bottom-right { + bottom: 0; + right: 0; +} + +.edge-top, +.edge-bottom { + left: var(--corner-size); + right: var(--corner-size); + height: var(--corner-size); + background-size: auto 100%; + background-repeat: repeat-x; + image-rendering: pixelated; + background-color: transparent; /* Ensure edges are transparent */ +} + +.edge-top { + top: 0; +} + +.edge-bottom { + bottom: 0; +} + +.edge-left, +.edge-right { + top: var(--corner-size); + bottom: var(--corner-size); + width: var(--corner-size); + background-size: 100% auto; + background-repeat: repeat-y; + image-rendering: pixelated; + background-color: transparent; /* Ensure edges are transparent */ +} + +.edge-left { + left: 0; +} + +.edge-right { + right: 0; +} + +.center { + top: var(--corner-size); + bottom: var(--corner-size); + left: var(--corner-size); + right: var(--corner-size); + background-size: contain; + background-repeat: repeat; + image-rendering: pixelated; + background-color: transparent; /* Ensure center is transparent */ +} + +#input-container { + font-family: 'PKMNems'; + display: flex; + flex-direction: column; + font-size: 16px; + padding: calc(var(--corner-size) - 2px); /* Adjust padding as necessary to fit within the border */ + position: relative; + z-index: 1; /* Ensure input-container appears above the background */ + box-sizing: border-box; /* Ensure padding is included in the width and height */ + background: transparent; /* Ensure input container is transparent */ +} + +.main-settings-block { + display: flex; + flex-direction: column; +} + +.settings-title { + font-weight: 700; + font-size: 18px; +} + +.input-item { + display: flex; + align-items: center; + padding-left: 10px; + font-size: var(--setting-text-size); +} + +.setting-label { + margin-right: 10px; +} + +.bool-label{ + width: 160px !important; +} + +.setting-options { + display: flex; + align-items: center; + flex-grow: 1; +} + +.setting-options .option { + width: 100%; + margin: 0 5px; + cursor: pointer; + text-align: center; + color: var(--white-main); /* Default color */ + text-shadow: 2px 2px 0 var(--white-sub); +} + +.setting-options .option.selected { + color: var(--red-main); /* Selected color */ + text-shadow: 2px 2px 0 var(--red-sub); +} + +.setting-label{ + color: var(--yellow-main); /* Focused color */ + text-shadow: 2px 2px 0 var(--white-sub); + font-family: 'PKMNems'; +} + +.setting-label.focus { + color: var(--yellow-main); /* Focused color */ + text-shadow: 2px 2px 0 var(--red-sub); + font-family: 'PKMNems'; +} + +#scaleSliderWrapper { + /* Optional styling for the scale slider wrapper */ +} + +#scaleSlider { + /* Optional styling for the scale slider */ +} + +#scaleValue { + font-family: 'PKMNems'; + font-size: 16px; +} + diff --git a/options/options.html b/options/options.html new file mode 100644 index 0000000..d3b3b8c --- /dev/null +++ b/options/options.html @@ -0,0 +1,26 @@ + + + + Rogue Dex Options + + + +

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + + + diff --git a/options/options.js b/options/options.js new file mode 100644 index 0000000..a6c0fa5 --- /dev/null +++ b/options/options.js @@ -0,0 +1,88 @@ +import OptionsManager from './optionsManager.js'; +import ImageInjector from './imageInjector.js'; +import generateSettingsUI from './generateSettingsUI.js'; + +document.addEventListener('DOMContentLoaded', () => { + generateSettingsUI(); + + const optionsManager = new OptionsManager(); + const imageInjector = new ImageInjector(); + + let focusedSettingIndex = 0; + const settings = document.querySelectorAll('.input-item'); + + const updateFocus = () => { + settings.forEach((setting, index) => { + const label = setting.querySelector('.setting-label'); + if (index === focusedSettingIndex) { + label.classList.add('focus'); + } else { + label.classList.remove('focus'); + } + }); + }; + + const handleOptionChange = (setting, directionOrValue) => { + const options = setting.querySelectorAll('.option'); + let selectedIndex = Array.from(options).findIndex(option => option.classList.contains('selected')); + if (directionOrValue === 'left' && selectedIndex > 0) { + selectedIndex -= 1; + } else if (directionOrValue === 'right' && selectedIndex < options.length - 1) { + selectedIndex += 1; + } else if ((directionOrValue !== "left" && directionOrValue !== "right")) { + selectedIndex = Array.from(options).findIndex(option => option.getAttribute('data-value') === directionOrValue); + } + options.forEach(option => option.classList.remove('selected')); + options[selectedIndex].classList.add('selected'); + + const option = options[selectedIndex]; + const settingName = option.getAttribute('data-setting'); + const value = option.getAttribute('data-value'); + + optionsManager.saveOption(settingName, value); + + if (settingName === 'menuType') { + imageInjector.injectImages(parseInt(value, 10)); + } else if (settingName === 'scaleFactor') { + optionsManager.updateScale(value); + } + }; + + document.addEventListener('keydown', (event) => { + switch (event.key) { + case 'ArrowUp': + if (focusedSettingIndex > 0) { + focusedSettingIndex -= 1; + updateFocus(); + } + break; + case 'ArrowDown': + if (focusedSettingIndex < settings.length - 1) { + focusedSettingIndex += 1; + updateFocus(); + } + break; + case 'ArrowLeft': + handleOptionChange(settings[focusedSettingIndex], 'left'); + break; + case 'ArrowRight': + handleOptionChange(settings[focusedSettingIndex], 'right'); + break; + } + }); + + // Attach click event listeners to the options + document.querySelectorAll('.setting-options .option').forEach(option => { + option.addEventListener('click', (event) => { + const setting = event.target.closest('.input-item'); + focusedSettingIndex = Array.from(settings).indexOf(setting); + updateFocus(); + handleOptionChange(setting, event.target.getAttribute('data-value')); + }); + }); + + optionsManager.restoreOptions((menuType) => { + imageInjector.injectImages(menuType); + updateFocus(); + }); +}); diff --git a/options/optionsManager.js b/options/optionsManager.js new file mode 100644 index 0000000..eed01c3 --- /dev/null +++ b/options/optionsManager.js @@ -0,0 +1,81 @@ +import settingsTemplate from './settingsTemplate.js'; + +class OptionsManager { + constructor() { + this.browserApi = typeof browser !== "undefined" ? browser : chrome; + } + + saveOption(setting, value) { + const settings = {}; + if (setting === 'menuType' || setting === 'scaleFactor') { + settings[setting] = parseFloat(value); + } else if (value === 'true' || value === 'false') { + settings[setting] = value === 'true'; + } else { + settings[setting] = value; + } + this.browserApi.storage.sync.set(settings, () => { + if (this.browserApi.runtime.lastError) { + console.error('Error saving option:', this.browserApi.runtime.lastError); + } else { + console.log('Option saved successfully'); + } + }); + } + + restoreOptions(callback) { + const keys = Object.values(settingsTemplate).map(setting => setting.localStorage); + this.browserApi.storage.sync.get(keys, (data) => { + if (this.browserApi.runtime.lastError) { + console.error('Error retrieving options:', this.browserApi.runtime.lastError); + } else { + document.querySelectorAll('.setting-options .option').forEach(option => { + const setting = option.getAttribute('data-setting'); + const value = option.getAttribute('data-value'); + if (data[setting] === (setting === 'menuType' || setting === 'scaleFactor' ? parseFloat(value) : value === 'true')) { + option.classList.add('selected'); + } + }); + + if (callback) { + callback(data.menuType || 1); + } + } + }); + } + + updateScale(value) { + const scaleFactor = parseFloat(value); + document.getElementById('scaleValue').textContent = scaleFactor; + // Update any other necessary elements based on scale factor + } + + scaleElements() { + const manualScaleFactor = document.getElementById('scaleSlider').value; + document.getElementById('scaleValue').textContent = manualScaleFactor; + } + + saveOptions() { + const showMin = document.querySelector('.option[data-setting="showMinified"].selected').getAttribute('data-value') === 'true'; + const showEnemy = document.querySelector('.option[data-setting="showEnemies"].selected').getAttribute('data-value') === 'true'; + const showParty = document.querySelector('.option[data-setting="showParty"].selected').getAttribute('data-value') === 'true'; + const scaleFactor = document.getElementById('scaleSlider').value; + const menuType = parseInt(document.querySelector('.option[data-setting="menuType"].selected').getAttribute('data-value'), 10); + + this.browserApi.storage.sync.set({ + 'showMinified': showMin, + 'scaleFactor': scaleFactor, + 'showEnemies': showEnemy, + 'showParty': showParty, + 'menuType': menuType + }, () => { + if (this.browserApi.runtime.lastError) { + console.error('Error saving options:', this.browserApi.runtime.lastError); + } else { + console.log('Options saved successfully'); + } + }); + } +} + +export default OptionsManager; diff --git a/options/settingsTemplate.js b/options/settingsTemplate.js new file mode 100644 index 0000000..93d9248 --- /dev/null +++ b/options/settingsTemplate.js @@ -0,0 +1,35 @@ +const settingsTemplate = { + 0: { + text: "Use Minified", + options: ["No", "Yes"], + localStorage: "showMinified", + type: "Bool" + }, + 1: { + text: "Show Enemies", + options: ["No", "Yes"], + localStorage: "showEnemies", + type: "Bool" + }, + 2: { + text: "Show Party", + options: ["No", "Yes"], + localStorage: "showParty", + type: "Bool" + }, + 3: { + text: "Overlay Scale", + options: ["0.5", "1.0", "1.5", "2.0","2.5","3.0"], + appendText: "x", + localStorage: "scaleFactor", + type: "Float" + }, + 4: { + text: "Menu Type", + options: ["1", "2", "3", "4", "5"], + localStorage: "menuType", + type: "Int" + } +}; + +export default settingsTemplate; \ No newline at end of file diff --git a/styles.css b/styles.css index f2b2b62..9de1f4e 100644 --- a/styles.css +++ b/styles.css @@ -1,7 +1,7 @@ -:root { - --font-size: min(3vh, 2vw); - --icon-size: min(10vh, 6vw); -} +/*:root {*/ +/* --font-size: min(3vh, 2vw);*/ +/* --icon-size: min(10vh, 6vw);*/ +/*}*/ .allies-team { margin: 0 auto; @@ -38,8 +38,8 @@ } .pokemon-icon img { - width: min(var(--icon-size), 100px); - height: min(var(--icon-size), 100px); + width: 5em; + height: 5em; } .pokemon-info { @@ -53,24 +53,22 @@ } .type-icon { - --width: min(calc(var(--icon-size) / 2), 30px); - --height: min(calc(var(--icon-size) / 2), 30px); - width: var(--width); - height: var(--height); + width: 1.5em; + height: 1.5em; background-size: cover; background-repeat: no-repeat; background-position: left; - background-position-x: min(-0.03em, -1.15px); + background-position-x: -0.07em; border-radius: 50%; - margin: 0 5px; + margin: 0 0.3em; } .pokemon-weaknesses, .pokemon-resistances, .pokemon-immunities { - min-width: min(calc(var(--icon-size) / 2 + 1vh), 30px); + min-width: 2.5em; display: flex; - justify-content: center; + min-height: 5em; } .pokemon-weaknesses { @@ -100,8 +98,8 @@ .text-base { display: flex; font-family: 'emerald'; - font-size: min(var(--font-size), 18px); - text-shadow: 2px 0 #fff, -2px 0 #fff, 0 2px #fff, 0 -2px #fff, 1px 1px #fff, -1px -1px #fff, 1px -1px #fff, -1px 1px #fff; + font-size: 1em; + text-shadow: 0.1em 0 #fff, -0.1em 0 #fff, 0 0.1em #fff, 0 -0.1em #fff, 0.05em 0.05em #fff, -0.05em -0.05em #fff, 0.05em -0.05em #fff, -0.05em 0.05em #fff; color: black; } @@ -109,15 +107,15 @@ display: grid; } .arrow-button { - font-size: min(8vh, 45px) + font-size: 2.5em; } .tooltip .tooltiptext { visibility: hidden; text-align: center; border-radius: 6px; - padding: 5px 0; - font-size: var(--font-size); + padding: 0.25em 0; + font-size: 1em; position: absolute; z-index: 1; } @@ -130,7 +128,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { input[type='range'] { overflow: hidden; - width: 20vh; + width: 4em; -webkit-appearance: none; } @@ -172,4 +170,21 @@ input[type="range"] { text-align: center; color: blue; background-color: #ffffff50; +} + +.stat-p { + display: flex; + padding-right: 0.3em; + padding-top: 0.3em; +} + +.stat-c { + position: relative; + text-shadow: 0.1em 0 rgba(255, 255, 255, 0), -0.1em 0 rgba(255, 255, 255, 0), 0 0.1em rgba(255, 255, 255, 0), 0 -0.1em rgba(255, 255, 255, 0), 0.05em 0.05em rgba(255, 255, 255, 0), -0.05em -0.05em rgba(255, 255, 255, 0), 0.05em -0.05em rgba(255, 255, 255, 0), -0.05em 0.05em rgba(255, 255, 255, 0); +} + +.stat-icon { + position: absolute; + top: -0.3em; + right: -0.5em; } \ No newline at end of file From 0e685cbff815a4b2bc69d26d29f01353586c1aa4 Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 15:52:49 -0500 Subject: [PATCH 02/78] realtime delete for allies works now --- content/content.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/content/content.js b/content/content.js index 2eb6a06..a964e8b 100644 --- a/content/content.js +++ b/content/content.js @@ -345,20 +345,16 @@ function deleteAllChildren(element) { while (element.firstChild) { element.removeChild(element.firstChild); } + element.innerHTML = ''; } function deleteWrapperDivs() { try { console.log("DELETE CALLED") - // ['allies', 'enemies'].forEach((divId) => { - const enemies = document.getElementById("enemies"); - deleteAllChildren(enemies); - const allies = document.getElementById("allies"); + let enemies = document.getElementById("enemies"); deleteAllChildren(enemies); - // wrapperDivPositions[divId].top = div.style.top - // wrapperDivPositions[divId].left = div.style.left - // document.body.removeChild(div) - // }) + let allies = document.getElementById("allies"); + deleteAllChildren(allies); } catch (e) { console.error(e) } From 5565b60d51177ca7f26dd33ac66679e671c45abb Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 16:00:49 -0500 Subject: [PATCH 03/78] cleanup and showEnemies fix --- content/content.js | 2 + content/util_classes/localStorage.util.js | 139 +--------------------- 2 files changed, 3 insertions(+), 138 deletions(-) diff --git a/content/content.js b/content/content.js index a964e8b..fe9308e 100644 --- a/content/content.js +++ b/content/content.js @@ -352,6 +352,7 @@ function deleteWrapperDivs() { try { console.log("DELETE CALLED") let enemies = document.getElementById("enemies"); + console.log(enemies); deleteAllChildren(enemies); let allies = document.getElementById("allies"); deleteAllChildren(allies); @@ -379,6 +380,7 @@ async function scaleElements() { async function initCreation(sessionData) { deleteWrapperDivs(); let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); + console.log(extensionSettings); if (extensionSettings.showEnemies) { await dataMapping("enemyParty", "enemies", sessionData); } diff --git a/content/util_classes/localStorage.util.js b/content/util_classes/localStorage.util.js index 2096cd0..7b776ef 100644 --- a/content/util_classes/localStorage.util.js +++ b/content/util_classes/localStorage.util.js @@ -52,7 +52,7 @@ class LocalStorageClass { browserApi.storage.sync.set({ 'scaleFactor': 1 }); data.scaleFactor = 1; } - if (data.showEnemeies === undefined) { + if (data.showEnemies === undefined) { browserApi.storage.sync.set({ 'showEnemies': true }); data.showEnemeies = true; } @@ -65,143 +65,6 @@ class LocalStorageClass { }); } - // static #init($this) { - // // LocalStorageClass.#extensionSettingsListener($this); - // $this.dataKey = $this.getDataKey("data_"); - // //$this.sessionKey = $this.getKey("sessionData"); - // LocalStorageClass.#getExtensionSettings($this); - // } - // - // getDataKey(matchString) { - // const keys = Object.keys(localStorage); - // for (let i = 0; i < keys.length; i++) { - // const key = keys[i]; - // if (key.includes(matchString)) { - // return key; - // } - // } - // } - // - // clearLocalSessionData() { - // const keys = Object.keys(localStorage); - // for (let i = 0; i < keys.length; i++) { - // const key = keys[i]; - // if (key.includes("sessionData")) { - // localStorage.removeItem(key); - // } - // } - // console.log("LocalStorage Primed"); - // } - // - // determineSession(){ - // let $this = this; - // let slot = $this.tempSaveSlot.slot; - // let dataToMatch = $this.tempSaveSlot.slot; - // console.log($this.potentialSessions); - // for(let sI in $this.potentialSessions) { - // let curSessionKey = $this.potentialSessions[sI]; - // console.log(curSessionKey); - // let curSessionData = curSessionKey.data; - // if (curSessionData == dataToMatch) { - // //return curSessionKey.key; - // $this.sessionKey = curSessionKey.key; - // } - // else{ - // console.log("NO MATCH WITH SLOT: ", slot) - // } - // } - // } - // - // getPotentialSessionKeys(){ - // const keys = Object.keys(localStorage); - // let potentialSessions = []; - // for (let i = 0; i < keys.length; i++) { - // const key = keys[i]; - // console.log(key); - // if (key.includes("sessionData")) { - // let data = this.readLocalDataByKey(key); - // console.log(data); - // let potentialSettingsObject = {key: key, data: data} - // potentialSessions.push(potentialSettingsObject); - // } - // } - // - // this.potentialSessions = potentialSessions - // return potentialSessions; - // } - // - // - // static async #getExtensionSettings($this) { - // return new Promise((resolve) => { - // browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty'], (data) => { - // if (data.showMinified === undefined) { - // browserApi.storage.sync.set({ 'showMinified': false }); - // data.showMinified = false; - // } - // if (data.scaleFactor === undefined) { - // browserApi.storage.sync.set({ 'scaleFactor': 1 }); - // data.scaleFactor = 1; - // } - // if (data.showEnemeies === undefined) { - // browserApi.storage.sync.set({ 'showEnemies': true }); - // data.showEnemeies = true; - // } - // if (data.showParty === undefined) { - // browserApi.storage.sync.set({ 'showParty': true }); - // data.showParty = true; - // } - // resolve(data); - // }); - // }); - // } - // - // - // - // async getExtensionSettings(){ - // return await LocalStorageClass.#getExtensionSettings(this); - // } - // - // getSessionData(){ - // - // - // let data = this.getPotentialSessionKeys(); - // this.sessionKey = (data[0]).key; - // //console.log(this.sessionKey); - // //this.sessionKey = "sessionData2_ProSnow" - // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary - // let localStorageData = localStorage.getItem(this.sessionKey); - // const decryptedString = CryptoJS.AES.decrypt(localStorageData, saveKey).toString(CryptoJS.enc.Utf8); - // return JSON.parse(decryptedString); - // } - // - // setSessionData(sessionData) { - // //hard set - // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary - // const jsonString = JSON.stringify(sessionData); - // const encryptedString = CryptoJS.AES.encrypt(jsonString, saveKey).toString(); - // localStorage.setItem(this.sessionKey, encryptedString); - // } - // - // getPlayerData(){ - // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary - // let localStorageData = localStorage.getItem(this.dataKey); - // const decryptedString = CryptoJS.AES.decrypt(localStorageData, saveKey).toString(CryptoJS.enc.Utf8); - // return JSON.parse(decryptedString); - // } - // - // readLocalDataByKey(key){ - // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary - // let localStorageData = localStorage.getItem(key); - // const decryptedString = CryptoJS.AES.decrypt(localStorageData, saveKey).toString(CryptoJS.enc.Utf8); - // return JSON.parse(decryptedString); - // } - // - // setPlayerData(playerData) { - // const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary - // const jsonString = JSON.stringify(playerData); - // const encryptedString = CryptoJS.AES.encrypt(jsonString, saveKey).toString(); - // localStorage.setItem(this.dataKey, encryptedString); - // } } From 865d836095650dbf1f364a905e506f54f8673a87 Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 16:07:31 -0500 Subject: [PATCH 04/78] abilities fix --- content/util_classes/pokemonMapper.util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js index 01b1646..6ff90d6 100644 --- a/content/util_classes/pokemonMapper.util.js +++ b/content/util_classes/pokemonMapper.util.js @@ -197,7 +197,7 @@ class PokemonMapperClass{ immunities: Array.from(typeEffectiveness.immunities), }, ivs: pokemon.ivs, - ability: $this.I2A[pokemon.abilityIndex-1], + ability: $this.I2A[pokemon.abilityIndex], nature: $this.I2N[pokemon.nature], basePokemon: basePokemon, baseId: $this.P2I[basePokemon], From a6ba52493265d12673350e33282c655e82cec44e Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 17:28:46 -0500 Subject: [PATCH 05/78] rebasing p1 --- content/content.js | 285 +++++++++++---------- content/maps/PokemonEvolutions.js | 2 - content/maps/Pokemon_To_Id.js | 2 - content/maps/weatherMap.js | 2 - content/util_classes/pokemonMapper.util.js | 41 ++- 5 files changed, 175 insertions(+), 157 deletions(-) diff --git a/content/content.js b/content/content.js index fe9308e..ee72110 100644 --- a/content/content.js +++ b/content/content.js @@ -29,8 +29,6 @@ function initUtilities(e) { } else { console.log("Error Loading Scripts :(") } - //console.log(`isReady has changed to: ${Utils.isReady}`); - // Additional logic to handle the change }); } @@ -142,7 +140,7 @@ let Stat; Stat[Stat["SPDEF"] = 4] = "SPDEF"; Stat[Stat["SPD"] = 5] = "SPD"; })(Stat || (Stat = {})); -; + function createTooltipDiv(tip) { const tooltip = document.createElement('div') @@ -153,27 +151,47 @@ function createTooltipDiv(tip) { } // Current values: weaknesses, resistances, immunities -function createTypeEffectivenessWrapper(effectiveness, types) { - const typeEffectivenessWrapper = document.createElement('div') - typeEffectivenessWrapper.classList.add(`pokemon-${effectiveness}`); - typeEffectivenessWrapper.classList.add('tooltip'); - let counter = 0; - let block = document.createElement('div'); - typeEffectivenessWrapper.appendChild(block) - types.forEach(type => { - if (counter % 3 === 0) { - block = document.createElement('div'); - typeEffectivenessWrapper.appendChild(block) - } - const typeIcon = document.createElement('div'); - typeIcon.style.backgroundImage = `url('https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/types/generation-viii/sword-shield/${Types[type]}.png')`; - typeIcon.className = 'type-icon'; - block.appendChild(typeIcon) - counter += 1; - }); - return typeEffectivenessWrapper +function createTypeEffectivenessWrapper(typeEffectivenesses) { + let typesHTML = ` + ${Object.keys(typeEffectivenesses).map((effectiveness) => { + if (typeEffectivenesses[effectiveness].length === 0) return '' + const tooltipMap = { + weaknesses: "Weak to", + resistances: "Resists", + immunities: "Immune to" + }; + return ` +
+ + ${typeEffectivenesses[effectiveness].map((type, counter) => ` + ${/* The current html structure requires to wrap every third element in a div, the implementation here gets a bit ugly. */''} + ${((counter + 1) % 3 === 1) ? + `
` + : ''} + +
+ + ${/* Closing div, after every third element or when the arrays max length is reached. */''} + ${((counter + 1) % 3 === 0) || ((counter + 1) === typeEffectivenesses[effectiveness].length) ? + `
` + : ''} + `).join('')} + ${createTooltipDiv(tooltipMap[effectiveness] || "")} +
+ ` + }).join('')} + ` + return typesHTML +} + +function createTooltipDiv(tip) { + const tooltipHtml = ` +
${tip}
+ ` + return tooltipHtml } + const pages = { "enemies": 0, "allies": 0, @@ -182,48 +200,33 @@ const partySize = { "enemies": 0, "allies": 0 } -let currentEnemyPage = 0; -let currentAllyPage = 0; -let enemiesPokemon = []; -let alliesPokemon = []; let weather = {}; -function createArrowButtonsDiv(divId) { - const buttonsDiv = document.createElement('div') - buttonsDiv.classList.add('arrow-button-wrapper') - const arrowUpButton = document.createElement('button') - const arrowDownButton = document.createElement('button') - arrowUpButton.classList.add('text-base') - arrowDownButton.classList.add('text-base') - arrowUpButton.classList.add('arrow-button') - arrowDownButton.classList.add('arrow-button') - arrowUpButton.textContent = "↑" - arrowDownButton.textContent = "↓" - arrowUpButton.id = `${divId}-up` - arrowDownButton.id = `${divId}-down` - arrowUpButton.addEventListener('click', changePage) - arrowDownButton.addEventListener('click', changePage) - buttonsDiv.appendChild(arrowUpButton) - buttonsDiv.appendChild(arrowDownButton) - return buttonsDiv +function createArrowButtonsDiv(divId, upString, downString) { + let result = {}; + result.idUp = `${divId}-up` + result.idDown = `${divId}-down` + + result.html = ` +
+ + +
+ ` + + return result } -function createOpacitySliderDiv(divId, initialValue = "100") { - const sliderDiv = document.createElement('div') - sliderDiv.classList.add('slider-wrapper') - const opacityTextDiv = document.createElement('div') - opacityTextDiv.classList.add('text-base') - opacityTextDiv.textContent = "Opacity:" - const slider = document.createElement('input') - slider.type = "range" - slider.min = "10" - slider.max = "100" - slider.value = initialValue - slider.id = `${divId}-slider` - sliderDiv.appendChild(opacityTextDiv) - sliderDiv.appendChild(slider) - sliderDiv.addEventListener('input', changeOpacity) - return sliderDiv +function createOpacitySliderDiv(divId, initialValue = "100", min = "10", max = "100") { + let result = {}; + result.id = `${divId}-slider` + result.html = ` +
+
Opacity:
+ +
+ ` + return result } function changeOpacity(e) { @@ -238,17 +241,15 @@ async function changePage(click) { const divId = buttonId.split("-")[0] const direction = buttonId.split("-")[1] if (direction === 'up') { - if(pages[divId] > 0){ + if (pages[divId] > 0) { pages[divId] -= 1 - } - else{ + } else { pages[divId] = partySize[divId] } } else if (direction === 'down') { - if(pages[divId] < partySize[divId]) { + if (pages[divId] < partySize[divId]) { pages[divId] += 1 - } - else{ + } else { pages[divId] = partySize[divId] } } @@ -256,60 +257,56 @@ async function changePage(click) { await initCreation(sessionData); } -async function createPokemonCardDiv(divId, pokemon) { - console.log(pokemon); - const card = document.createElement('div'); - card.classList.add('pokemon-card'); - - const opacitySliderDiv = createOpacitySliderDiv(divId, wrapperDivPositions[divId].opacity) - - const infoRow = document.createElement('div'); - infoRow.style.display = 'flex'; - - const iconWrapper = document.createElement('div'); - iconWrapper.className = 'pokemon-icon'; - const icon = document.createElement('img'); - icon.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; - iconWrapper.appendChild(icon); - infoRow.appendChild(iconWrapper); - - console.log(pokemon); - const weaknessesWrapper = createTypeEffectivenessWrapper('weaknesses', pokemon.typeEffectiveness.weaknesses) - weaknessesWrapper.appendChild(createTooltipDiv('Weak to')) - - const resistancesWrapper = createTypeEffectivenessWrapper('resistances', pokemon.typeEffectiveness.resistances) - resistancesWrapper.appendChild(createTooltipDiv('Resists')) - - const immunitiesWrapper = createTypeEffectivenessWrapper('immunities', pokemon.typeEffectiveness.immunities) - immunitiesWrapper.appendChild(createTooltipDiv('Immune to')) - - infoRow.appendChild(weaknessesWrapper) - infoRow.appendChild(resistancesWrapper) - infoRow.appendChild(immunitiesWrapper) - - const extraInfoRow = document.createElement('div'); - extraInfoRow.classList.add('text-base') - extraInfoRow.textContent = `Ability: ${pokemon.ability} - Nature: ${pokemon.nature}`; - - const ivsRow = document.createElement('div'); - ivsRow.classList.add('text-base'); - ivsRow.textContent = `HP: ${pokemon.ivs[Stat["HP"]]}, ATK: ${pokemon.ivs[Stat["ATK"]]}, DEF: ${pokemon.ivs[Stat["DEF"]]}, SPE: ${pokemon.ivs[Stat["SPD"]]}, SPD: ${pokemon.ivs[Stat["SPDEF"]]}, SPA: ${pokemon.ivs[Stat["SPATK"]]}`; - - let weatherRow = undefined - if (weather.type && weather.turnsLeft) { - weatherRow = document.createElement('div'); - weatherRow.classList.add('text-base'); - weatherRow.textContent = `Weather: ${weather.type}, Turns Left: ${weather.turnsLeft}` - } - - card.appendChild(opacitySliderDiv) - card.appendChild(infoRow) - card.appendChild(extraInfoRow) - card.appendChild(ivsRow) - if (weatherRow) { - card.appendChild(weatherRow) - } - return card +async function createPokemonCardDiv(cardId, pokemon) { + let opacityRangeMin = 10; + let opacityRangeMax = 100; + let pokemonImageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; + const opacitySlider = createOpacitySliderDiv(cardId, wrapperDivPositions[cardId].opacity, opacityRangeMin, opacityRangeMax); + const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness); + let cardHTML = ` +
+
+ ${opacitySlider.html} +
+
+ +
+ + ${/* Displays the 3 type effectiveness segemtns (weaknesses, resistances, immunities). */''} + ${typeEffectivenessHTML} + +
+ +
+
+ Ability: ${pokemon.ability.name} + ${createTooltipDiv(pokemon.ability.description)} +
+  -  +
+ Nature: ${pokemon.nature} + ${createTooltipDiv("")} +
+
+
+ HP: ${pokemon.ivs[Stat["HP"]]}, ATK: ${pokemon.ivs[Stat["ATK"]]}, DEF: ${pokemon.ivs[Stat["DEF"]]} +
+
+ SPE: ${pokemon.ivs[Stat["SPD"]]}, SPD: ${pokemon.ivs[Stat["SPDEF"]]}, SPA: ${pokemon.ivs[Stat["SPATK"]]} +
+ + ${(weather.type && weather.turnsLeft) ? + `
Weather: ${weather.type}, Turns Left: ${weather.turnsLeft}
` + : ''} +
+
+ ` + + const cardObj = {} + cardObj.html = cardHTML; + cardObj.slider = opacitySlider.id; + + return cardObj } function createWrapperDiv(divId) { @@ -327,17 +324,32 @@ function createWrapperDiv(divId) { return newDiv; } + async function createCardsDiv(divId, pokemon) { - let newDiv = createWrapperDiv(divId) - let buttonsDiv = createArrowButtonsDiv(divId) - newDiv.appendChild(buttonsDiv) - const pokemonCards = document.createElement("div"); - pokemonCards.className = "pokemon-cards" - const card = await createPokemonCardDiv(divId, pokemon); - pokemonCards.appendChild(card); - newDiv.appendChild(pokemonCards) - document.body.appendChild(newDiv) + let newDiv = createWrapperDiv(divId); + let divClass = divId === 'enemies' ? 'enemy-team' : 'allies-team' + const cardObj = await createPokemonCardDiv(divId, pokemon); + const buttonsObj = createArrowButtonsDiv(divId, "↑", "↓"); + const cardsHTML = ` + ${buttonsObj.html} + ${cardObj.html} + `; + newDiv.insertAdjacentHTML("afterbegin", cardsHTML) + document.body.appendChild(newDiv); + document.getElementById(cardObj.slider).addEventListener('input', changeOpacity) + // document.getElementById(buttonsObj.idUp).addEventListener('click', changePage) + // document.getElementById(buttonsObj.idDown).addEventListener('click', changePage) return newDiv + // let newDiv = createWrapperDiv(divId) + // let buttonsDiv = createArrowButtonsDiv(divId) + // newDiv.appendChild(buttonsDiv) + // const pokemonCards = document.createElement("div"); + // pokemonCards.className = "pokemon-cards" + // const card = await createPokemonCardDiv(divId, pokemon); + // pokemonCards.appendChild(card); + // newDiv.appendChild(pokemonCards) + // document.body.appendChild(newDiv) + // return newDiv } @@ -377,6 +389,7 @@ async function scaleElements() { enemiesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; alliesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; } + async function initCreation(sessionData) { deleteWrapperDivs(); let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); @@ -384,12 +397,12 @@ async function initCreation(sessionData) { if (extensionSettings.showEnemies) { await dataMapping("enemyParty", "enemies", sessionData); } - if(extensionSettings.showParty){ + if (extensionSettings.showParty) { await dataMapping("party", "allies", sessionData); } } -async function dataMapping(pokemonLocation, divId, sessionData){ +async function dataMapping(pokemonLocation, divId, sessionData) { await Utils.PokeMapper.getPokemonArray(sessionData[pokemonLocation], sessionData.arena).then(async (pokemonData) => { weather = pokemonData.hasOwnProperty('weather') ? pokemonData.weather : null; partySize[divId] = pokemonData.pokemon.length; @@ -400,17 +413,16 @@ async function dataMapping(pokemonLocation, divId, sessionData){ }); } -function determinePage(divId, pokemon){ - if(pages[divId] >= pokemon.length){ +function determinePage(divId, pokemon) { + if (pages[divId] >= pokemon.length) { pages[divId] = pokemon.length - 1; return pages[divId]; - } - else{ + } else { return pages[divId]; } } -function extensionSettingsListener(){ +function extensionSettingsListener() { browserApi.storage.onChanged.addListener(async function (changes, namespace) { for (let [key, {oldValue, newValue}] of Object.entries(changes)) { if (key === 'showMinified') { @@ -433,7 +445,6 @@ function extensionSettingsListener(){ } - function touchControlListener() { const touchControlsElement = document.getElementById('touchControls') if (touchControlsElement) { diff --git a/content/maps/PokemonEvolutions.js b/content/maps/PokemonEvolutions.js index 640c792..940a373 100644 --- a/content/maps/PokemonEvolutions.js +++ b/content/maps/PokemonEvolutions.js @@ -477,5 +477,3 @@ window["__EvolutionMap"] = { SNOM: {name: "FROSMOTH", val: 1}, GIMMIGHOUL: {name: "GHOLDENGO", val: 1} }; - -// export default EvolutionMap; \ No newline at end of file diff --git a/content/maps/Pokemon_To_Id.js b/content/maps/Pokemon_To_Id.js index 0923049..af7d9dc 100644 --- a/content/maps/Pokemon_To_Id.js +++ b/content/maps/Pokemon_To_Id.js @@ -1082,5 +1082,3 @@ window["__Species"] = { PALDEA_WOOPER: 8194, BLOODMOON_URSALUNA: 8901, }; - -// export default Species; \ No newline at end of file diff --git a/content/maps/weatherMap.js b/content/maps/weatherMap.js index a5a61be..efa61e6 100644 --- a/content/maps/weatherMap.js +++ b/content/maps/weatherMap.js @@ -10,5 +10,3 @@ window["__WeatherMap"] = { HARSH_SUN: 8, STRONG_WINDS: 9 }; - -// export default WeatherMap; \ No newline at end of file diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js index 6ff90d6..bb88f34 100644 --- a/content/util_classes/pokemonMapper.util.js +++ b/content/util_classes/pokemonMapper.util.js @@ -1,9 +1,3 @@ -// import Species from "./Pokemon_To_Id"; -// import EvolutionMap from "./PokemonEvolutions"; -// import WeatherMap from "./weatherMap"; -// import AbilityMap from "./abilityMap"; -// import NatureMap from "./natureMap"; - class PokemonMapperClass{ constructor() { this.P2I = window.__Species; @@ -20,16 +14,11 @@ class PokemonMapperClass{ } static #init($this){ - //let $this = this; $this.I2P = PokemonMapperClass.#calculateInverseMap($this.P2I); $this.I2W = PokemonMapperClass.#calculateInverseMap($this.W2I); $this.I2A = PokemonMapperClass.#calculateInverseMap($this.A2I); $this.I2N = PokemonMapperClass.#calculateInverseMap($this.N2I); $this.PrevoMap = PokemonMapperClass.#calcPrevolution($this.EvoMap); - // console.log($this.P2I); - // console.log($this.I2P); - // console.log($this.EvoMap); - // console.log($this.PrevoMap); } static #calculateInverseMap(map){ @@ -171,6 +160,32 @@ class PokemonMapperClass{ return { weaknesses, resistances, immunities }; } + async getPokemonAbility(pokemonId, abilityIndex) { + let pokeID = (this.I2P[pokemonId]).toLowerCase(); + try { + const pokemonInfo = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokeID}`); + const data = await pokemonInfo.json(); + + const abilityLength = data.abilities.length + + if (abilityIndex >= abilityLength) { + abilityIndex = abilityLength - 1 // Pokerogue uses a "None" ability as padding when pokémon have less than 3. + } + + const abilityName = data.abilities[abilityIndex].ability.name + const abilityInfo = await fetch(`https://pokeapi.co/api/v2/ability/${abilityName}`); + const abilityData = await abilityInfo.json(); + return { + 'name': abilityName.toUpperCase().replace('-', ' '), + 'description': abilityData.flavor_text_entries[abilityData.flavor_text_entries.length - 1].flavor_text, + 'isHidden': data.abilities[abilityIndex].is_hidden + } + } catch (error) { + console.error('Error fetching Pokémons ability:', error); + return null; + } + } + async getPokemonArray(pokemonData, arena) { let $this = this; let pokemonArray = PokemonMapperClass.#mapPartyToPokemonArray(pokemonData); @@ -197,7 +212,7 @@ class PokemonMapperClass{ immunities: Array.from(typeEffectiveness.immunities), }, ivs: pokemon.ivs, - ability: $this.I2A[pokemon.abilityIndex], + ability: await $this.getPokemonAbility(pokemon.species, pokemon.abilityIndex), nature: $this.I2N[pokemon.nature], basePokemon: basePokemon, baseId: $this.P2I[basePokemon], @@ -278,6 +293,4 @@ class PokemonMapperClass{ } -//const __PokemonMapper = new PokemonMapperClass(); - From d93676b3eb85591514b59a489d494708e8f2615a Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 18:09:38 -0500 Subject: [PATCH 06/78] fixed slider on chrome --- content/content.js | 11 ++++++++--- styles.css | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/content/content.js b/content/content.js index ee72110..40920b5 100644 --- a/content/content.js +++ b/content/content.js @@ -223,7 +223,7 @@ function createOpacitySliderDiv(divId, initialValue = "100", min = "10", max = " result.html = `
Opacity:
- +
` return result @@ -307,6 +307,7 @@ async function createPokemonCardDiv(cardId, pokemon) { cardObj.slider = opacitySlider.id; return cardObj + } function createWrapperDiv(divId) { @@ -337,8 +338,12 @@ async function createCardsDiv(divId, pokemon) { newDiv.insertAdjacentHTML("afterbegin", cardsHTML) document.body.appendChild(newDiv); document.getElementById(cardObj.slider).addEventListener('input', changeOpacity) - // document.getElementById(buttonsObj.idUp).addEventListener('click', changePage) - // document.getElementById(buttonsObj.idDown).addEventListener('click', changePage) + document.getElementById(buttonsObj.idUp).addEventListener('click', (event)=>{ + changePage(event); + }) + document.getElementById(buttonsObj.idDown).addEventListener('click', (event)=>{ + changePage(event); + }) return newDiv // let newDiv = createWrapperDiv(divId) // let buttonsDiv = createArrowButtonsDiv(divId) diff --git a/styles.css b/styles.css index 9de1f4e..c0e49b6 100644 --- a/styles.css +++ b/styles.css @@ -132,20 +132,20 @@ -webkit-appearance: none; } - input[type='range']::-webkit-slider-runnable-track { - height: 1vh; - -webkit-appearance: none; - color: #13bba4; - margin-top: -1px; - } + /*input[type='range']::-webkit-slider-runnable-track {*/ + /* height: 0.1em;*/ + /* -webkit-appearance: none;*/ + /* color: #13bba4;*/ + /* margin-top: -1px;*/ + /*}*/ - input[type='range']::-webkit-slider-thumb { - width: 1vh; - -webkit-appearance: none; - height: 1vh; - cursor: ew-resize; - box-shadow: -8vh 0 0 8vh #b3462c; - } + /*input[type='range']::-webkit-slider-thumb {*/ + /* width: .1em;*/ + /* -webkit-appearance: none;*/ + /* height: 1vh;*/ + /* cursor: ew-resize;*/ + /* box-shadow: -.8em 0 0 .8em #b3462c;*/ + /*}*/ } /** FF*/ @@ -172,6 +172,19 @@ input[type="range"] { background-color: #ffffff50; } +.hidden-ability { + color: #f700ff; +} + +.running-status { + position: absolute; + width: 100%; + justify-content: center; + text-align: center; + color: blue; + background-color: #ffffff50; +} + .stat-p { display: flex; padding-right: 0.3em; @@ -187,4 +200,8 @@ input[type="range"] { position: absolute; top: -0.3em; right: -0.5em; +} + +.op-slider{ + width: 100% !important; } \ No newline at end of file From 54f9d60da94ac2aa05cbf97ef0389f09007f393c Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 18:22:17 -0500 Subject: [PATCH 07/78] tooltip fix --- styles.css | 1 + 1 file changed, 1 insertion(+) diff --git a/styles.css b/styles.css index c0e49b6..1dd38bf 100644 --- a/styles.css +++ b/styles.css @@ -118,6 +118,7 @@ font-size: 1em; position: absolute; z-index: 1; + background-color: white; } .tooltip:hover .tooltiptext { From 31b91239e5edfe82163af3ede7a402c8f46fe926 Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 22:44:38 -0500 Subject: [PATCH 08/78] added minified version & fusion names --- content/content.js | 163 +++++++++++++++++---- content/util_classes/localStorage.util.js | 16 ++ content/util_classes/pokemonMapper.util.js | 99 ++++++++++++- styles.css | 13 +- 4 files changed, 255 insertions(+), 36 deletions(-) diff --git a/content/content.js b/content/content.js index 40920b5..1fbd658 100644 --- a/content/content.js +++ b/content/content.js @@ -202,13 +202,16 @@ const partySize = { } let weather = {}; -function createArrowButtonsDiv(divId, upString, downString) { +function createArrowButtonsDiv(divId, upString, downString, showMinified) { + let sizes = "2.5em !important" + if(showMinified){ + sizes = "1em !important" + } let result = {}; result.idUp = `${divId}-up` result.idDown = `${divId}-down` - result.html = ` -
+
@@ -271,8 +274,6 @@ async function createPokemonCardDiv(cardId, pokemon) {
- - ${/* Displays the 3 type effectiveness segemtns (weaknesses, resistances, immunities). */''} ${typeEffectivenessHTML}
@@ -307,7 +308,86 @@ async function createPokemonCardDiv(cardId, pokemon) { cardObj.slider = opacitySlider.id; return cardObj +} +function generateIVsHTML(pokemon, dexIvs){ + let fullHTML = ``; + for (let i in pokemon.ivs) { + let curIV = pokemon.ivs[i]; + fullHTML += `
${Stat[i]}: 
${curIV}${ivComparison(curIV, dexIvs[i])}
  
`; + // ivsRow.appendChild(statDiv); + } + return fullHTML; +} + +function ivComparison(pokeIv, dexIv) { + let iconA = ""; + let colorS = "#00FF00"; + if(pokeIv > dexIv){ + iconA = "↑"; + colorS = "#00FF00"; + } + else if (pokeIv < dexIv) { + iconA = "↓"; + colorS = "#FF0000"; + } + else{ + iconA = "-"; + colorS = "#FFFF00"; + } + let returnHTML = `
${iconA}
` + return returnHTML; +} + +async function createPokemonCardDiv_minified(cardId, pokemon) { + let savedData = Utils.LocalStorage.getPlayerData(); + let dexData = savedData["dexData"]; + let dexIvs = dexData[pokemon.baseId]["ivs"]; + console.log(savedData); + let opacityRangeMin = 10; + let opacityRangeMax = 100; + let pokemonImageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; + const opacitySlider = createOpacitySliderDiv(cardId, wrapperDivPositions[cardId].opacity, opacityRangeMin, opacityRangeMax); + const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness); + let ivsGeneratedHTML = generateIVsHTML(pokemon, dexIvs); + //${opacitySlider.html} + //
+ //
+ // + //
+ // // ${typeEffectivenessHTML} + // + //
+ let cardHTML = ` +
+
+
${pokemon.name}
+
+
+ Ability: ${pokemon.ability.name} + ${createTooltipDiv(pokemon.ability.description)} +
+  -  +
+ Nature: ${pokemon.nature} + ${createTooltipDiv("")} +
+
+
+ ${ivsGeneratedHTML} +
+ + ${(weather.type && weather.turnsLeft) ? + `
Weather: ${weather.type}, Turns Left: ${weather.turnsLeft}
` + : ''} +
+
+ ` + + const cardObj = {} + cardObj.html = cardHTML; + //cardObj.slider = opacitySlider.id; + return cardObj } function createWrapperDiv(divId) { @@ -325,36 +405,62 @@ function createWrapperDiv(divId) { return newDiv; } +function getColor(num) { + if (num < 0 || num > 31) { + throw new Error('Number must be between 0 and 31'); + } + + // Calculate the red component: It decreases as 'num' increases + let red = Math.floor(255 * (1 - num / 31)); + // Calculate the green component: It increases as 'num' increases + let green = Math.floor(255 * (num / 31)); + // Blue component is always 0 for a red to green gradient + let blue = 0; + + // Convert each color component to a hex string and pad with 0 if necessary + let redHex = red.toString(16).padStart(2, '0'); + let greenHex = green.toString(16).padStart(2, '0'); + let blueHex = blue.toString(16).padStart(2, '0'); + + // Combine the hex values and return the result + return `#${redHex}${greenHex}${blueHex}`; +} + + +async function chooseCardType(divId, pokemon, minified){ + if(minified){ + return cardsObj = await createPokemonCardDiv_minified(divId, pokemon); + } + else{ + return cardsObj = await createPokemonCardDiv(divId, pokemon); + } +} async function createCardsDiv(divId, pokemon) { + let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); let newDiv = createWrapperDiv(divId); - let divClass = divId === 'enemies' ? 'enemy-team' : 'allies-team' - const cardObj = await createPokemonCardDiv(divId, pokemon); - const buttonsObj = createArrowButtonsDiv(divId, "↑", "↓"); - const cardsHTML = ` + return await chooseCardType(divId, pokemon, extensionSettings.showMinified).then(async (cardObj) =>{ + const buttonsObj = createArrowButtonsDiv(divId, "↑", "↓", extensionSettings.showMinified); + const cardsHTML = ` ${buttonsObj.html} ${cardObj.html} `; - newDiv.insertAdjacentHTML("afterbegin", cardsHTML) - document.body.appendChild(newDiv); - document.getElementById(cardObj.slider).addEventListener('input', changeOpacity) - document.getElementById(buttonsObj.idUp).addEventListener('click', (event)=>{ - changePage(event); - }) - document.getElementById(buttonsObj.idDown).addEventListener('click', (event)=>{ - changePage(event); + newDiv.insertAdjacentHTML("afterbegin", cardsHTML) + document.body.appendChild(newDiv); + if(cardObj.slider) { + document.getElementById(cardObj.slider).addEventListener('input', changeOpacity) + } + document.getElementById(buttonsObj.idUp).addEventListener('click', (event)=>{ + changePage(event); + }) + document.getElementById(buttonsObj.idDown).addEventListener('click', (event)=>{ + changePage(event); + }) + return newDiv }) - return newDiv - // let newDiv = createWrapperDiv(divId) - // let buttonsDiv = createArrowButtonsDiv(divId) - // newDiv.appendChild(buttonsDiv) - // const pokemonCards = document.createElement("div"); - // pokemonCards.className = "pokemon-cards" - // const card = await createPokemonCardDiv(divId, pokemon); - // pokemonCards.appendChild(card); - // newDiv.appendChild(pokemonCards) - // document.body.appendChild(newDiv) - // return newDiv + + + } @@ -398,7 +504,6 @@ async function scaleElements() { async function initCreation(sessionData) { deleteWrapperDivs(); let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); - console.log(extensionSettings); if (extensionSettings.showEnemies) { await dataMapping("enemyParty", "enemies", sessionData); } diff --git a/content/util_classes/localStorage.util.js b/content/util_classes/localStorage.util.js index 7b776ef..b7a84ca 100644 --- a/content/util_classes/localStorage.util.js +++ b/content/util_classes/localStorage.util.js @@ -65,6 +65,22 @@ class LocalStorageClass { }); } + getPlayerData(){ + let localStorageData = localStorage.getItem(this.getDataKey('data_')); + const decryptedString = CryptoJS.AES.decrypt(localStorageData, this.saveKey).toString(CryptoJS.enc.Utf8); + return JSON.parse(decryptedString); + } + + getDataKey(matchString) { + const keys = Object.keys(localStorage); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + if (key.includes(matchString)) { + return key; + } + } + } + } diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js index bb88f34..fe8db21 100644 --- a/content/util_classes/pokemonMapper.util.js +++ b/content/util_classes/pokemonMapper.util.js @@ -63,7 +63,9 @@ class PokemonMapperClass{ ivs: pokemon.ivs, pokerus: pokemon.pokerus, shiny: pokemon.shiny, - variant: pokemon.variant + variant: pokemon.variant, + fusionSpecies: (pokemon.hasOwnProperty('fusionSpecies')) ? pokemon.fusionSpecies : null, + fusionAbilityIndex: pokemon.fusionAbilityIndex, })); } @@ -160,8 +162,17 @@ class PokemonMapperClass{ return { weaknesses, resistances, immunities }; } - async getPokemonAbility(pokemonId, abilityIndex) { - let pokeID = (this.I2P[pokemonId]).toLowerCase(); + async getPokemonAbility(pokemonId, pokemonAbilityIndex, fusionId, fusionAbilityIndex) { + let pokeID; + let abilityIndex; + if(fusionId){ + pokeID = (this.I2P[fusionId]).toLowerCase(); + abilityIndex = fusionAbilityIndex; + } + else{ + pokeID = (this.I2P[pokemonId]).toLowerCase(); + abilityIndex = pokemonAbilityIndex; + } try { const pokemonInfo = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokeID}`); const data = await pokemonInfo.json(); @@ -186,9 +197,15 @@ class PokemonMapperClass{ } } + capitalizeFirstLetter(string) { + string = string.toLowerCase(); + return string.charAt(0).toUpperCase() + string.slice(1); + } + async getPokemonArray(pokemonData, arena) { let $this = this; let pokemonArray = PokemonMapperClass.#mapPartyToPokemonArray(pokemonData); + console.log(pokemonArray); let frontendPokemonArray = []; let weather = {}; @@ -203,16 +220,17 @@ class PokemonMapperClass{ const pokemonId = $this.I2P[$this.convertPokemonId(pokemon.species)].toLocaleLowerCase(); const typeEffectiveness = await PokemonMapperClass.#getPokemonTypeEffectiveness($this, pokemonId); let basePokemon = $this.findBasePokemon($this.I2P[pokemon.species]); + let name = $this.getPokemonName(pokemon); return { id: pokemon.species, - name: $this.I2P[pokemon.species], + name: $this.capitalizeFirstLetter(name.toUpperCase()), typeEffectiveness: { weaknesses: Array.from(typeEffectiveness.weaknesses), resistances: Array.from(typeEffectiveness.resistances), immunities: Array.from(typeEffectiveness.immunities), }, ivs: pokemon.ivs, - ability: await $this.getPokemonAbility(pokemon.species, pokemon.abilityIndex), + ability: await $this.getPokemonAbility(pokemon.species, pokemon.abilityIndex, pokemon.fusionSpecies, pokemon.fusionAbilityIndex), nature: $this.I2N[pokemon.nature], basePokemon: basePokemon, baseId: $this.P2I[basePokemon], @@ -224,6 +242,77 @@ class PokemonMapperClass{ return { pokemon: frontendPokemonArray, weather: weather }; } + getPokemonName(pokemon){ + if(pokemon.fusionSpecies){ + let nameA = this.I2P[pokemon.species]; + let nameB = this.I2P[pokemon.fusionSpecies]; + return this.getFusedSpeciesName(nameA, nameB); + //getFusedSpeciesName + } + else{ + return this.I2P[pokemon.species] + } + + } + + getFusedSpeciesName(speciesAName, speciesBName) { + const fragAPattern = /([a-z]{2}.*?[aeiou(?:y$)\-\']+)(.*?)$/i; + const fragBPattern = /([a-z]{2}.*?[aeiou(?:y$)\-\'])(.*?)$/i; + + const [ speciesAPrefixMatch, speciesBPrefixMatch ] = [ speciesAName, speciesBName ].map(n => /^(?:[^ ]+) /.exec(n)); + const [ speciesAPrefix, speciesBPrefix ] = [ speciesAPrefixMatch, speciesBPrefixMatch ].map(m => m ? m[0] : ''); + + if (speciesAPrefix) + speciesAName = speciesAName.slice(speciesAPrefix.length); + if (speciesBPrefix) + speciesBName = speciesBName.slice(speciesBPrefix.length); + + const [ speciesASuffixMatch, speciesBSuffixMatch ] = [ speciesAName, speciesBName ].map(n => / (?:[^ ]+)$/.exec(n)); + const [ speciesASuffix, speciesBSuffix ] = [ speciesASuffixMatch, speciesBSuffixMatch ].map(m => m ? m[0] : ''); + + if (speciesASuffix) + speciesAName = speciesAName.slice(0, -speciesASuffix.length); + if (speciesBSuffix) + speciesBName = speciesBName.slice(0, -speciesBSuffix.length); + + const splitNameA = speciesAName.split(/ /g); + const splitNameB = speciesBName.split(/ /g); + + let fragAMatch = fragAPattern.exec(speciesAName); + let fragBMatch = fragBPattern.exec(speciesBName); + let fragA; + let fragB; + + fragA = splitNameA.length === 1 + ? fragAMatch ? fragAMatch[1] : speciesAName + : splitNameA[splitNameA.length - 1]; + + if (splitNameB.length === 1) { + if (fragBMatch) { + const lastCharA = fragA.slice(fragA.length - 1); + const prevCharB = fragBMatch[1].slice(fragBMatch.length - 1); + fragB = (/[\-']/.test(prevCharB) ? prevCharB : '') + fragBMatch[2] || prevCharB; + if (lastCharA === fragB[0]) { + if (/[aiu]/.test(lastCharA)) + fragB = fragB.slice(1); + else { + const newCharMatch = new RegExp(`[^${lastCharA}]`).exec(fragB); + if (newCharMatch?.index > 0) + fragB = fragB.slice(newCharMatch.index); + } + } + } else + fragB = speciesBName; + } else + fragB = splitNameB[splitNameB.length - 1]; + + if (splitNameA.length > 1) + fragA = `${splitNameA.slice(0, splitNameA.length - 1).join(' ')} ${fragA}`; + + fragB = `${fragB.slice(0, 1).toLowerCase()}${fragB.slice(1)}`; + return `${speciesAPrefix || speciesBPrefix}${fragA}${fragB}${speciesBSuffix || speciesASuffix}`; + } + convertPokemonId(pokemonId) { const conversionList = { 2019: 10091, diff --git a/styles.css b/styles.css index 1dd38bf..bc2c84e 100644 --- a/styles.css +++ b/styles.css @@ -22,6 +22,10 @@ display: flex; } +.stat-cont{ + +} + .pokemon-cards { display: flex; flex-wrap: nowrap; @@ -106,8 +110,13 @@ .arrow-button-wrapper { display: grid; } -.arrow-button { - font-size: 2.5em; +/*.arrow-button {*/ +/* font-size: 2.5em;*/ +/*}*/ + +.centered-flex{ + display: flex; + justify-content: center; } .tooltip .tooltiptext { From 15cc2545cdfffd21647a4a994eac34cc29984822 Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Sun, 19 May 2024 23:10:24 -0500 Subject: [PATCH 09/78] fusion sprite now work --- content/content.js | 51 ++++++++++++++++++++-- content/util_classes/pokemonMapper.util.js | 1 + 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/content/content.js b/content/content.js index 1fbd658..773bc2e 100644 --- a/content/content.js +++ b/content/content.js @@ -263,6 +263,7 @@ async function changePage(click) { async function createPokemonCardDiv(cardId, pokemon) { let opacityRangeMin = 10; let opacityRangeMax = 100; + // getPokemonIcon(pokemon); let pokemonImageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; const opacitySlider = createOpacitySliderDiv(cardId, wrapperDivPositions[cardId].opacity, opacityRangeMin, opacityRangeMax); const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness); @@ -271,9 +272,8 @@ async function createPokemonCardDiv(cardId, pokemon) {
${opacitySlider.html}
-
- -
+ + ${typeEffectivenessHTML}
@@ -339,6 +339,50 @@ function ivComparison(pokeIv, dexIv) { return returnHTML; } +function getPokemonIcon(pokemon, divId) { + const canvas = document.getElementById(`pokemon-icon_${divId}`); + const ctx = canvas.getContext('2d'); + const parent = canvas.parentElement; + const image1 = new Image(); + const image2 = new Image(); + + const loadImage = (image, src) => { + return new Promise((resolve, reject) => { + image.onload = () => resolve(image); + image.onerror = () => reject(new Error(`Failed to load image from ${src}`)); + image.src = src; + }); + }; + + const drawImages = () => { + const width = image1.width; + const height = image1.height; + const parentHeight = parent.clientHeight; + const canvasWidth = parentHeight * (width / height); + + // Set canvas dimensions based on the parent's height to allow scaling + canvas.width = canvasWidth; + canvas.height = parentHeight; + + if (pokemon.fusionId) { + ctx.drawImage(image1, 0, 0, width, height / 2, 0, 0, canvasWidth, parentHeight / 2); + ctx.drawImage(image2, 0, height / 2, width, height / 2, 0, parentHeight / 2, canvasWidth, parentHeight / 2); + } else { + ctx.drawImage(image1, 0, 0, width, height, 0, 0, canvasWidth, parentHeight); + } + }; + const image1Src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; + const image2Src = pokemon.fusionId ? `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.fusionId}.png` : null; + loadImage(image1, image1Src) + .then(() => image2Src ? loadImage(image2, image2Src) : null) + .then(drawImages) + .catch(error => console.error(error)); +} + + + + + async function createPokemonCardDiv_minified(cardId, pokemon) { let savedData = Utils.LocalStorage.getPlayerData(); let dexData = savedData["dexData"]; @@ -447,6 +491,7 @@ async function createCardsDiv(divId, pokemon) { `; newDiv.insertAdjacentHTML("afterbegin", cardsHTML) document.body.appendChild(newDiv); + getPokemonIcon(pokemon, divId); if(cardObj.slider) { document.getElementById(cardObj.slider).addEventListener('input', changeOpacity) } diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js index fe8db21..140463c 100644 --- a/content/util_classes/pokemonMapper.util.js +++ b/content/util_classes/pokemonMapper.util.js @@ -234,6 +234,7 @@ class PokemonMapperClass{ nature: $this.I2N[pokemon.nature], basePokemon: basePokemon, baseId: $this.P2I[basePokemon], + fusionId: pokemon.fusionSpecies, }; }); From db9425a2949d2210ad34c95584531b1fa490d1bc Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Mon, 20 May 2024 12:39:41 -0500 Subject: [PATCH 10/78] testing fireFox --- background.js | 86 +++++++--- content/content.js | 188 ++++++++++++++++----- content/util_classes/pokemonMapper.util.js | 29 +++- manifest.json | 65 +++++++ manifest_chrome.json | 74 ++++++++ options/imageInjector.js | 2 +- 6 files changed, 366 insertions(+), 78 deletions(-) create mode 100644 manifest.json create mode 100644 manifest_chrome.json diff --git a/background.js b/background.js index d477509..4f1a950 100644 --- a/background.js +++ b/background.js @@ -577,33 +577,63 @@ function appendPokemonArrayToDiv(pokemonArray, arena, message) { }) } -browserApi.runtime.onMessage.addListener(function(request, sender, sendResponse) { - // Happens when loading a savegame or continuing an old run - if (request.type == 'BG_GET_SAVEDATA') { - const savedata = request.data - slotId = request.slotId - console.log("Received save data", savedata) - appendPokemonArrayToDiv(mapPartyToPokemonArray(savedata.enemyParty), savedata.arena, "UPDATE_ENEMIES_DIV") - appendPokemonArrayToDiv(mapPartyToPokemonArray(savedata.party), savedata.arena, "UPDATE_ALLIES_DIV") - } -}); +// browserApi.runtime.onMessage.addListener(function(request, sender, sendResponse) { +// // Happens when loading a savegame or continuing an old run +// if (request.type == 'BG_GET_SAVEDATA') { +// const savedata = request.data +// slotId = request.slotId +// console.log("Received save data", savedata) +// appendPokemonArrayToDiv(mapPartyToPokemonArray(savedata.enemyParty), savedata.arena, "UPDATE_ENEMIES_DIV") +// appendPokemonArrayToDiv(mapPartyToPokemonArray(savedata.party), savedata.arena, "UPDATE_ALLIES_DIV") +// } +// }); -browserApi.webRequest.onBeforeRequest.addListener( - function(details) { - if (details.method === 'POST') { - try { - let sessionData = JSON.parse(new TextDecoder().decode(details.requestBody.raw[0].bytes)) - console.log("POST Session data:", sessionData) - if (details.url.includes("updateall")) sessionData = sessionData.session - appendPokemonArrayToDiv(mapPartyToPokemonArray(sessionData.enemyParty), sessionData.arena, "UPDATE_ENEMIES_DIV") - appendPokemonArrayToDiv(mapPartyToPokemonArray(sessionData.party), sessionData.arena, "UPDATE_ALLIES_DIV") - } catch (e) { - console.error("Error while intercepting web request: ", e) - } +browserApi.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === "fetchFusionImageHtml") { + const fusionUrl = `https://if.daena.me/find/?head=${request.pokemonId}&body=${request.fusionId}`; + + fetch(fusionUrl, { method: 'GET', redirect: 'follow' }) + .then(response => { + if (response.status === 307 || response.status === 200) { + return fetch(response.url).then(res => res.text()); + } else { + throw new Error(`Unexpected status code: ${response.status}`); + } + }) + .then(html => { + sendResponse({ success: true, html: html }); + }) + .catch(error => { + console.error("Fetch error:", error); + sendResponse({ success: false, error: error.message }); + }); + + // Return true to indicate you wish to send a response asynchronously + return true; } - }, - { - urls: ['https://api.pokerogue.net/savedata/update?datatype=1*', 'https://api.pokerogue.net/savedata/updateall'] - }, - ["requestBody"] -) \ No newline at end of file +}); + + + + + + +// browserApi.webRequest.onBeforeRequest.addListener( +// function(details) { +// if (details.method === 'POST') { +// try { +// let sessionData = JSON.parse(new TextDecoder().decode(details.requestBody.raw[0].bytes)) +// console.log("POST Session data:", sessionData) +// if (details.url.includes("updateall")) sessionData = sessionData.session +// appendPokemonArrayToDiv(mapPartyToPokemonArray(sessionData.enemyParty), sessionData.arena, "UPDATE_ENEMIES_DIV") +// appendPokemonArrayToDiv(mapPartyToPokemonArray(sessionData.party), sessionData.arena, "UPDATE_ALLIES_DIV") +// } catch (e) { +// console.error("Error while intercepting web request: ", e) +// } +// } +// }, +// { +// urls: ['https://api.pokerogue.net/savedata/update?datatype=1*', 'https://api.pokerogue.net/savedata/updateall'] +// }, +// ["requestBody"] +// ) \ No newline at end of file diff --git a/content/content.js b/content/content.js index 773bc2e..f1a1b8b 100644 --- a/content/content.js +++ b/content/content.js @@ -341,48 +341,113 @@ function ivComparison(pokeIv, dexIv) { function getPokemonIcon(pokemon, divId) { const canvas = document.getElementById(`pokemon-icon_${divId}`); - const ctx = canvas.getContext('2d'); - const parent = canvas.parentElement; - const image1 = new Image(); - const image2 = new Image(); - - const loadImage = (image, src) => { - return new Promise((resolve, reject) => { - image.onload = () => resolve(image); - image.onerror = () => reject(new Error(`Failed to load image from ${src}`)); - image.src = src; - }); - }; + if(canvas) { + const ctx = canvas.getContext('2d'); + const parent = canvas.parentElement; + const image1 = new Image(); + const image2 = new Image(); + const fusionImage = new Image(); + + const loadImage = (image, src) => { + return new Promise((resolve, reject) => { + image.onload = () => resolve(image); + image.onerror = () => reject(new Error(`Failed to load image from ${src}`)); + image.src = src; + }); + }; - const drawImages = () => { - const width = image1.width; - const height = image1.height; - const parentHeight = parent.clientHeight; - const canvasWidth = parentHeight * (width / height); + const drawSingleImage = (image) => { + const width = image.width; + const height = image.height; + const parentHeight = parent.clientHeight; + const canvasWidth = parentHeight * (width / height); - // Set canvas dimensions based on the parent's height to allow scaling - canvas.width = canvasWidth; - canvas.height = parentHeight; + // Set canvas dimensions based on the parent's height + canvas.width = canvasWidth; + canvas.height = parentHeight; - if (pokemon.fusionId) { + // Draw the full image + ctx.drawImage(image, 0, 0, width, height, 0, 0, canvasWidth, parentHeight); + }; + + const drawCombinedImages = () => { + const width = image1.width; + const height = image1.height; + const parentHeight = parent.clientHeight; + const canvasWidth = parentHeight * (width / height); + + // Set canvas dimensions based on the parent's height + canvas.width = canvasWidth; + canvas.height = parentHeight; + + // Draw the top half of the first image ctx.drawImage(image1, 0, 0, width, height / 2, 0, 0, canvasWidth, parentHeight / 2); + + // Draw the bottom half of the second image ctx.drawImage(image2, 0, height / 2, width, height / 2, 0, parentHeight / 2, canvasWidth, parentHeight / 2); + }; + + const image1Src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; + const image2Src = pokemon.fusionId ? `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.fusionId}.png` : null; + + if (pokemon.fusionId) { + let fusionName = Utils.PokeMapper.capitalizeFirstLetter((Utils.PokeMapper.I2P[pokemon.fusionId])); + let pokeName = Utils.PokeMapper.capitalizeFirstLetter((Utils.PokeMapper.I2P[pokemon.id])); + chrome.runtime.sendMessage({ + action: "fetchFusionImageHtml", + fusionId: fusionName, + pokemonId: pokeName + }, response => { + if (response.success) { + const parser = new DOMParser(); + console.log(response.html); + const doc = parser.parseFromString(response.html, 'text/html'); + const figure = doc.querySelector('figure.sprite.sprite-variant-main'); + console.log(figure); + if (figure) { + const img = figure.querySelector('img'); + if (img) { + loadImage(fusionImage, img.src) + .then(() => drawSingleImage(fusionImage)) + .catch(() => { + // Fallback to combined images method if fusion image fails to load + Promise.all([ + loadImage(image1, image1Src), + loadImage(image2, image2Src) + ]) + .then(drawCombinedImages) + .catch(error => console.error(error)); + }); + return; + } + } + } + // Fallback to combined images method if fusion image not found + Promise.all([ + loadImage(image1, image1Src), + loadImage(image2, image2Src) + ]) + .then(drawCombinedImages) + .catch(error => console.error(error)); + }); } else { - ctx.drawImage(image1, 0, 0, width, height, 0, 0, canvasWidth, parentHeight); + // If fusionId is null, just load and display the single image + loadImage(image1, image1Src) + .then(drawSingleImage) + .catch(error => console.error(error)); } - }; - const image1Src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; - const image2Src = pokemon.fusionId ? `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.fusionId}.png` : null; - loadImage(image1, image1Src) - .then(() => image2Src ? loadImage(image2, image2Src) : null) - .then(drawImages) - .catch(error => console.error(error)); + } + console.log(pokemon); } + + + + async function createPokemonCardDiv_minified(cardId, pokemon) { let savedData = Utils.LocalStorage.getPlayerData(); let dexData = savedData["dexData"]; @@ -600,14 +665,45 @@ function extensionSettingsListener() { } -function touchControlListener() { - const touchControlsElement = document.getElementById('touchControls') - if (touchControlsElement) { - const observer = new MutationObserver((mutations) => { - mutations.forEach(async (mutation) => { - if (mutation.type === 'attributes' && mutation.attributeName === 'data-ui-mode') { - const newValue = touchControlsElement.getAttribute('data-ui-mode'); - console.log('New data-ui-mode:', newValue); +// function touchControlListener() { +// const touchControlsElement = document.getElementById('touchControls'); +// console.log("Touch control listener called"); +// if (touchControlsElement) { +// const observer = new MutationObserver((mutations) => { +// mutations.forEach(async (mutation) => { +// if (mutation.type === 'attributes' && mutation.attributeName === 'data-ui-mode') { +// const newValue = touchControlsElement.getAttribute('data-ui-mode'); +// console.log('New data-ui-mode:', newValue); +// if (newValue === "MESSAGE" || newValue === "COMMAND" || newValue === "CONFIRM") { +// Utils.LocalStorage.setSessionData(); +// let sessionData = Utils.LocalStorage.getSessionData(); +// await initCreation(sessionData); +// } +// if (newValue === "SAVE_SLOT") { +// Utils.LocalStorage.clearAllSessionData(); +// } +// if (newValue === "SAVE_SLOT" || newValue === "TITLE" || newValue === "MODIFIER_SELECT" || newValue === "STARTER_SELECT") { +// deleteWrapperDivs() +// } +// } +// }); +// }); +// +// window.addEventListener('resize', scaleElements); +// observer.observe(touchControlsElement, {attributes: true}); +// } +// } + +function listenForDataUiModeChange() { + function observeTouchControls() { + const touchControlsElement = document.getElementById('touchControls'); + if (touchControlsElement) { + const observer = new MutationObserver((mutations) => { + mutations.forEach(async (mutation) => { + if (mutation.type === 'attributes' && mutation.attributeName === 'data-ui-mode') { + const newValue = touchControlsElement.getAttribute('data-ui-mode'); + console.log('New value:', newValue); + // Existing logic for handling data-ui-mode changes if (newValue === "MESSAGE" || newValue === "COMMAND" || newValue === "CONFIRM") { Utils.LocalStorage.setSessionData(); let sessionData = Utils.LocalStorage.getSessionData(); @@ -619,12 +715,22 @@ function touchControlListener() { if (newValue === "SAVE_SLOT" || newValue === "TITLE" || newValue === "MODIFIER_SELECT" || newValue === "STARTER_SELECT") { deleteWrapperDivs() } - } + + } + }); }); - }); - window.addEventListener('resize', scaleElements); - observer.observe(touchControlsElement, {attributes: true}); + observer.observe(touchControlsElement, { attributes: true }); + console.log('Touch control listener called'); + } else { + console.error('Element with ID "touchControls" not found.'); + // Retry after a short delay if the element might be added later + setTimeout(observeTouchControls, 1000); + } } + + observeTouchControls(); } +listenForDataUiModeChange(); + diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js index 140463c..9952e47 100644 --- a/content/util_classes/pokemonMapper.util.js +++ b/content/util_classes/pokemonMapper.util.js @@ -70,17 +70,30 @@ class PokemonMapperClass{ } static async #getPokeType(id) { - try { - const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`); - const data = await response.json(); - const types = data.types.map(type => type.type.name); - return types; - } catch (error) { - console.error('Error fetching Pokémon type:', error); - return null; + console.log(id); + const maxRetries = 3; + let attempts = 0; + while (attempts < maxRetries) { + try { + const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + const types = data.types.map(type => type.type.name); + return types; + } catch (error) { + attempts += 1; + console.error(`Attempt ${attempts} - Error fetching Pokémon type:`, error); + if (attempts >= maxRetries) { + console.error('Max retries reached. Failed to fetch Pokémon type.'); + return null; + } + } } } + static async #getPokemonTypeEffectiveness($this, id) { const types = await PokemonMapperClass.#getPokeType(id); if (types) { diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..fcec742 --- /dev/null +++ b/manifest.json @@ -0,0 +1,65 @@ +{ + "manifest_version": 2, + "name": "Rogue Dex", + "version": "2.6", + "permissions": [ + "activeTab", + "webRequest", + "storage", + "https://pokerogue.net/*", + "https://api.pokerogue.net/*" + ], + "browser_specific_settings": { + "gecko": { + "id": "{46029ed0-cb54-4130-8105-fcbbed40adc1}" + } + }, + "options_page": "options/options.html", + "options_ui": { + "page": "options/options.html", + "open_in_tab": false + }, + "browser_action": { + "default_popup": "options/options.html", + "default_icon": "./RogueDex.png", + "default_title": "RogueDex" + }, + "background": { + "scripts": ["background.js"], + "persistent": true + }, + "content_scripts": [ + { + "matches": ["https://api.pokerogue.net/*", "https://pokerogue.net/*"], + "js" : [ + "inject.js" + ], + "run_at": "document_start", + "all_frames": true + }, + { + "matches": ["https://pokerogue.net/*"], + "js" : [ + "content/utils.js", + "libs/crypto-js.min.js", + "content/maps/abilityMap.js", + "content/maps/natureMap.js", + "content/maps/Pokemon_To_Id.js", + "content/maps/weatherMap.js", + "content/maps/PokemonEvolutions.js", + "content/util_classes/pokemonMapper.util.js", + "content/util_classes/localStorage.util.js", + "content/content.js" + ], + "type": "module", + "css": ["styles.css"] + } + ], + "web_accessible_resources": [ + "inject.js", + "injected.js", + "content/*", + "fonts/*", + "images/*" + ] +} \ No newline at end of file diff --git a/manifest_chrome.json b/manifest_chrome.json new file mode 100644 index 0000000..119140d --- /dev/null +++ b/manifest_chrome.json @@ -0,0 +1,74 @@ +{ + "manifest_version": 3, + "name": "Rogue Dex", + "version": "2.6", + "permissions": [ + "activeTab", + "webRequest", + "storage" + ], + "host_permissions": [ + "https://pokerogue.net/*", + "https://api.pokerogue.net/*" + ], + "options_page": "options/options.html", + "options_ui": { + "page": "options/options.html", + "open_in_tab": false + }, + "action": { + "default_popup": "options/options.html" + }, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [ + "https://api.pokerogue.net/*", + "https://pokerogue.net/*" + ], + "js": [ + "inject.js" + ], + "run_at": "document_start", + "all_frames": true + }, + { + "matches": [ + "https://pokerogue.net/*" + ], + "js": [ + "content/utils.js", + "libs/crypto-js.min.js", + "content/maps/abilityMap.js", + "content/maps/natureMap.js", + "content/maps/Pokemon_To_Id.js", + "content/maps/weatherMap.js", + "content/maps/PokemonEvolutions.js", + "content/util_classes/pokemonMapper.util.js", + "content/util_classes/localStorage.util.js", + "content/content.js" + ], + "type": "module", + "css": [ + "styles.css" + ] + } + ], + "web_accessible_resources": [ + { + "resources": [ + "inject.js", + "injected.js", + "content/*", + "images/*", + "fonts/*" + ], + "matches": [ + "" + ], + "extension_ids": [] + } + ] +} diff --git a/options/imageInjector.js b/options/imageInjector.js index 367fcd2..6392295 100644 --- a/options/imageInjector.js +++ b/options/imageInjector.js @@ -23,7 +23,7 @@ export default class ImageInjector { parts.forEach(part => { const img = new Image(); - const url = `chrome-extension://${this.extensionId}/images/menu/${menuType}/${part}.png`; + const url = this.browserApi.extension.getURL(`images/menu/${menuType}/${part}.png`); img.src = url; this.preloadedImages[menuType][part] = img; }); From 7aa0c34bd2e413f42dd248eb64f6da04bb9fdd7e Mon Sep 17 00:00:00 2001 From: Devin Gearing Date: Mon, 20 May 2024 15:47:29 -0500 Subject: [PATCH 11/78] minor cleanup --- .gitignore | 1 - background.js | 651 +--------------------- content/content.js | 172 ++++-- content/util_classes/localStorage.util.js | 21 + inject.js | 12 - injected.js | 42 +- manifest.json | 61 +- manifest_chrome.json | 74 --- manifest_firefox.json | 34 +- options/imageInjector.js | 3 +- options/options.css | 2 + styles.css | 8 + 12 files changed, 264 insertions(+), 817 deletions(-) delete mode 100644 manifest_chrome.json diff --git a/.gitignore b/.gitignore index 40c3c4a..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +0,0 @@ -manifest.json \ No newline at end of file diff --git a/background.js b/background.js index 4f1a950..f9b1fca 100644 --- a/background.js +++ b/background.js @@ -1,639 +1,42 @@ const browserApi = typeof browser !== "undefined" ? browser : chrome; -let slotId = -1 -let Abilities; -(function (Abilities) { - Abilities[Abilities["NONE"] = 0] = "NONE"; - Abilities[Abilities["STENCH"] = 1] = "STENCH"; - Abilities[Abilities["DRIZZLE"] = 2] = "DRIZZLE"; - Abilities[Abilities["SPEED_BOOST"] = 3] = "SPEED_BOOST"; - Abilities[Abilities["BATTLE_ARMOR"] = 4] = "BATTLE_ARMOR"; - Abilities[Abilities["STURDY"] = 5] = "STURDY"; - Abilities[Abilities["DAMP"] = 6] = "DAMP"; - Abilities[Abilities["LIMBER"] = 7] = "LIMBER"; - Abilities[Abilities["SAND_VEIL"] = 8] = "SAND_VEIL"; - Abilities[Abilities["STATIC"] = 9] = "STATIC"; - Abilities[Abilities["VOLT_ABSORB"] = 10] = "VOLT_ABSORB"; - Abilities[Abilities["WATER_ABSORB"] = 11] = "WATER_ABSORB"; - Abilities[Abilities["OBLIVIOUS"] = 12] = "OBLIVIOUS"; - Abilities[Abilities["CLOUD_NINE"] = 13] = "CLOUD_NINE"; - Abilities[Abilities["COMPOUND_EYES"] = 14] = "COMPOUND_EYES"; - Abilities[Abilities["INSOMNIA"] = 15] = "INSOMNIA"; - Abilities[Abilities["COLOR_CHANGE"] = 16] = "COLOR_CHANGE"; - Abilities[Abilities["IMMUNITY"] = 17] = "IMMUNITY"; - Abilities[Abilities["FLASH_FIRE"] = 18] = "FLASH_FIRE"; - Abilities[Abilities["SHIELD_DUST"] = 19] = "SHIELD_DUST"; - Abilities[Abilities["OWN_TEMPO"] = 20] = "OWN_TEMPO"; - Abilities[Abilities["SUCTION_CUPS"] = 21] = "SUCTION_CUPS"; - Abilities[Abilities["INTIMIDATE"] = 22] = "INTIMIDATE"; - Abilities[Abilities["SHADOW_TAG"] = 23] = "SHADOW_TAG"; - Abilities[Abilities["ROUGH_SKIN"] = 24] = "ROUGH_SKIN"; - Abilities[Abilities["WONDER_GUARD"] = 25] = "WONDER_GUARD"; - Abilities[Abilities["LEVITATE"] = 26] = "LEVITATE"; - Abilities[Abilities["EFFECT_SPORE"] = 27] = "EFFECT_SPORE"; - Abilities[Abilities["SYNCHRONIZE"] = 28] = "SYNCHRONIZE"; - Abilities[Abilities["CLEAR_BODY"] = 29] = "CLEAR_BODY"; - Abilities[Abilities["NATURAL_CURE"] = 30] = "NATURAL_CURE"; - Abilities[Abilities["LIGHTNING_ROD"] = 31] = "LIGHTNING_ROD"; - Abilities[Abilities["SERENE_GRACE"] = 32] = "SERENE_GRACE"; - Abilities[Abilities["SWIFT_SWIM"] = 33] = "SWIFT_SWIM"; - Abilities[Abilities["CHLOROPHYLL"] = 34] = "CHLOROPHYLL"; - Abilities[Abilities["ILLUMINATE"] = 35] = "ILLUMINATE"; - Abilities[Abilities["TRACE"] = 36] = "TRACE"; - Abilities[Abilities["HUGE_POWER"] = 37] = "HUGE_POWER"; - Abilities[Abilities["POISON_POINT"] = 38] = "POISON_POINT"; - Abilities[Abilities["INNER_FOCUS"] = 39] = "INNER_FOCUS"; - Abilities[Abilities["MAGMA_ARMOR"] = 40] = "MAGMA_ARMOR"; - Abilities[Abilities["WATER_VEIL"] = 41] = "WATER_VEIL"; - Abilities[Abilities["MAGNET_PULL"] = 42] = "MAGNET_PULL"; - Abilities[Abilities["SOUNDPROOF"] = 43] = "SOUNDPROOF"; - Abilities[Abilities["RAIN_DISH"] = 44] = "RAIN_DISH"; - Abilities[Abilities["SAND_STREAM"] = 45] = "SAND_STREAM"; - Abilities[Abilities["PRESSURE"] = 46] = "PRESSURE"; - Abilities[Abilities["THICK_FAT"] = 47] = "THICK_FAT"; - Abilities[Abilities["EARLY_BIRD"] = 48] = "EARLY_BIRD"; - Abilities[Abilities["FLAME_BODY"] = 49] = "FLAME_BODY"; - Abilities[Abilities["RUN_AWAY"] = 50] = "RUN_AWAY"; - Abilities[Abilities["KEEN_EYE"] = 51] = "KEEN_EYE"; - Abilities[Abilities["HYPER_CUTTER"] = 52] = "HYPER_CUTTER"; - Abilities[Abilities["PICKUP"] = 53] = "PICKUP"; - Abilities[Abilities["TRUANT"] = 54] = "TRUANT"; - Abilities[Abilities["HUSTLE"] = 55] = "HUSTLE"; - Abilities[Abilities["CUTE_CHARM"] = 56] = "CUTE_CHARM"; - Abilities[Abilities["PLUS"] = 57] = "PLUS"; - Abilities[Abilities["MINUS"] = 58] = "MINUS"; - Abilities[Abilities["FORECAST"] = 59] = "FORECAST"; - Abilities[Abilities["STICKY_HOLD"] = 60] = "STICKY_HOLD"; - Abilities[Abilities["SHED_SKIN"] = 61] = "SHED_SKIN"; - Abilities[Abilities["GUTS"] = 62] = "GUTS"; - Abilities[Abilities["MARVEL_SCALE"] = 63] = "MARVEL_SCALE"; - Abilities[Abilities["LIQUID_OOZE"] = 64] = "LIQUID_OOZE"; - Abilities[Abilities["OVERGROW"] = 65] = "OVERGROW"; - Abilities[Abilities["BLAZE"] = 66] = "BLAZE"; - Abilities[Abilities["TORRENT"] = 67] = "TORRENT"; - Abilities[Abilities["SWARM"] = 68] = "SWARM"; - Abilities[Abilities["ROCK_HEAD"] = 69] = "ROCK_HEAD"; - Abilities[Abilities["DROUGHT"] = 70] = "DROUGHT"; - Abilities[Abilities["ARENA_TRAP"] = 71] = "ARENA_TRAP"; - Abilities[Abilities["VITAL_SPIRIT"] = 72] = "VITAL_SPIRIT"; - Abilities[Abilities["WHITE_SMOKE"] = 73] = "WHITE_SMOKE"; - Abilities[Abilities["PURE_POWER"] = 74] = "PURE_POWER"; - Abilities[Abilities["SHELL_ARMOR"] = 75] = "SHELL_ARMOR"; - Abilities[Abilities["AIR_LOCK"] = 76] = "AIR_LOCK"; - Abilities[Abilities["TANGLED_FEET"] = 77] = "TANGLED_FEET"; - Abilities[Abilities["MOTOR_DRIVE"] = 78] = "MOTOR_DRIVE"; - Abilities[Abilities["RIVALRY"] = 79] = "RIVALRY"; - Abilities[Abilities["STEADFAST"] = 80] = "STEADFAST"; - Abilities[Abilities["SNOW_CLOAK"] = 81] = "SNOW_CLOAK"; - Abilities[Abilities["GLUTTONY"] = 82] = "GLUTTONY"; - Abilities[Abilities["ANGER_POINT"] = 83] = "ANGER_POINT"; - Abilities[Abilities["UNBURDEN"] = 84] = "UNBURDEN"; - Abilities[Abilities["HEATPROOF"] = 85] = "HEATPROOF"; - Abilities[Abilities["SIMPLE"] = 86] = "SIMPLE"; - Abilities[Abilities["DRY_SKIN"] = 87] = "DRY_SKIN"; - Abilities[Abilities["DOWNLOAD"] = 88] = "DOWNLOAD"; - Abilities[Abilities["IRON_FIST"] = 89] = "IRON_FIST"; - Abilities[Abilities["POISON_HEAL"] = 90] = "POISON_HEAL"; - Abilities[Abilities["ADAPTABILITY"] = 91] = "ADAPTABILITY"; - Abilities[Abilities["SKILL_LINK"] = 92] = "SKILL_LINK"; - Abilities[Abilities["HYDRATION"] = 93] = "HYDRATION"; - Abilities[Abilities["SOLAR_POWER"] = 94] = "SOLAR_POWER"; - Abilities[Abilities["QUICK_FEET"] = 95] = "QUICK_FEET"; - Abilities[Abilities["NORMALIZE"] = 96] = "NORMALIZE"; - Abilities[Abilities["SNIPER"] = 97] = "SNIPER"; - Abilities[Abilities["MAGIC_GUARD"] = 98] = "MAGIC_GUARD"; - Abilities[Abilities["NO_GUARD"] = 99] = "NO_GUARD"; - Abilities[Abilities["STALL"] = 100] = "STALL"; - Abilities[Abilities["TECHNICIAN"] = 101] = "TECHNICIAN"; - Abilities[Abilities["LEAF_GUARD"] = 102] = "LEAF_GUARD"; - Abilities[Abilities["KLUTZ"] = 103] = "KLUTZ"; - Abilities[Abilities["MOLD_BREAKER"] = 104] = "MOLD_BREAKER"; - Abilities[Abilities["SUPER_LUCK"] = 105] = "SUPER_LUCK"; - Abilities[Abilities["AFTERMATH"] = 106] = "AFTERMATH"; - Abilities[Abilities["ANTICIPATION"] = 107] = "ANTICIPATION"; - Abilities[Abilities["FOREWARN"] = 108] = "FOREWARN"; - Abilities[Abilities["UNAWARE"] = 109] = "UNAWARE"; - Abilities[Abilities["TINTED_LENS"] = 110] = "TINTED_LENS"; - Abilities[Abilities["FILTER"] = 111] = "FILTER"; - Abilities[Abilities["SLOW_START"] = 112] = "SLOW_START"; - Abilities[Abilities["SCRAPPY"] = 113] = "SCRAPPY"; - Abilities[Abilities["STORM_DRAIN"] = 114] = "STORM_DRAIN"; - Abilities[Abilities["ICE_BODY"] = 115] = "ICE_BODY"; - Abilities[Abilities["SOLID_ROCK"] = 116] = "SOLID_ROCK"; - Abilities[Abilities["SNOW_WARNING"] = 117] = "SNOW_WARNING"; - Abilities[Abilities["HONEY_GATHER"] = 118] = "HONEY_GATHER"; - Abilities[Abilities["FRISK"] = 119] = "FRISK"; - Abilities[Abilities["RECKLESS"] = 120] = "RECKLESS"; - Abilities[Abilities["MULTITYPE"] = 121] = "MULTITYPE"; - Abilities[Abilities["FLOWER_GIFT"] = 122] = "FLOWER_GIFT"; - Abilities[Abilities["BAD_DREAMS"] = 123] = "BAD_DREAMS"; - Abilities[Abilities["PICKPOCKET"] = 124] = "PICKPOCKET"; - Abilities[Abilities["SHEER_FORCE"] = 125] = "SHEER_FORCE"; - Abilities[Abilities["CONTRARY"] = 126] = "CONTRARY"; - Abilities[Abilities["UNNERVE"] = 127] = "UNNERVE"; - Abilities[Abilities["DEFIANT"] = 128] = "DEFIANT"; - Abilities[Abilities["DEFEATIST"] = 129] = "DEFEATIST"; - Abilities[Abilities["CURSED_BODY"] = 130] = "CURSED_BODY"; - Abilities[Abilities["HEALER"] = 131] = "HEALER"; - Abilities[Abilities["FRIEND_GUARD"] = 132] = "FRIEND_GUARD"; - Abilities[Abilities["WEAK_ARMOR"] = 133] = "WEAK_ARMOR"; - Abilities[Abilities["HEAVY_METAL"] = 134] = "HEAVY_METAL"; - Abilities[Abilities["LIGHT_METAL"] = 135] = "LIGHT_METAL"; - Abilities[Abilities["MULTISCALE"] = 136] = "MULTISCALE"; - Abilities[Abilities["TOXIC_BOOST"] = 137] = "TOXIC_BOOST"; - Abilities[Abilities["FLARE_BOOST"] = 138] = "FLARE_BOOST"; - Abilities[Abilities["HARVEST"] = 139] = "HARVEST"; - Abilities[Abilities["TELEPATHY"] = 140] = "TELEPATHY"; - Abilities[Abilities["MOODY"] = 141] = "MOODY"; - Abilities[Abilities["OVERCOAT"] = 142] = "OVERCOAT"; - Abilities[Abilities["POISON_TOUCH"] = 143] = "POISON_TOUCH"; - Abilities[Abilities["REGENERATOR"] = 144] = "REGENERATOR"; - Abilities[Abilities["BIG_PECKS"] = 145] = "BIG_PECKS"; - Abilities[Abilities["SAND_RUSH"] = 146] = "SAND_RUSH"; - Abilities[Abilities["WONDER_SKIN"] = 147] = "WONDER_SKIN"; - Abilities[Abilities["ANALYTIC"] = 148] = "ANALYTIC"; - Abilities[Abilities["ILLUSION"] = 149] = "ILLUSION"; - Abilities[Abilities["IMPOSTER"] = 150] = "IMPOSTER"; - Abilities[Abilities["INFILTRATOR"] = 151] = "INFILTRATOR"; - Abilities[Abilities["MUMMY"] = 152] = "MUMMY"; - Abilities[Abilities["MOXIE"] = 153] = "MOXIE"; - Abilities[Abilities["JUSTIFIED"] = 154] = "JUSTIFIED"; - Abilities[Abilities["RATTLED"] = 155] = "RATTLED"; - Abilities[Abilities["MAGIC_BOUNCE"] = 156] = "MAGIC_BOUNCE"; - Abilities[Abilities["SAP_SIPPER"] = 157] = "SAP_SIPPER"; - Abilities[Abilities["PRANKSTER"] = 158] = "PRANKSTER"; - Abilities[Abilities["SAND_FORCE"] = 159] = "SAND_FORCE"; - Abilities[Abilities["IRON_BARBS"] = 160] = "IRON_BARBS"; - Abilities[Abilities["ZEN_MODE"] = 161] = "ZEN_MODE"; - Abilities[Abilities["VICTORY_STAR"] = 162] = "VICTORY_STAR"; - Abilities[Abilities["TURBOBLAZE"] = 163] = "TURBOBLAZE"; - Abilities[Abilities["TERAVOLT"] = 164] = "TERAVOLT"; - Abilities[Abilities["AROMA_VEIL"] = 165] = "AROMA_VEIL"; - Abilities[Abilities["FLOWER_VEIL"] = 166] = "FLOWER_VEIL"; - Abilities[Abilities["CHEEK_POUCH"] = 167] = "CHEEK_POUCH"; - Abilities[Abilities["PROTEAN"] = 168] = "PROTEAN"; - Abilities[Abilities["FUR_COAT"] = 169] = "FUR_COAT"; - Abilities[Abilities["MAGICIAN"] = 170] = "MAGICIAN"; - Abilities[Abilities["BULLETPROOF"] = 171] = "BULLETPROOF"; - Abilities[Abilities["COMPETITIVE"] = 172] = "COMPETITIVE"; - Abilities[Abilities["STRONG_JAW"] = 173] = "STRONG_JAW"; - Abilities[Abilities["REFRIGERATE"] = 174] = "REFRIGERATE"; - Abilities[Abilities["SWEET_VEIL"] = 175] = "SWEET_VEIL"; - Abilities[Abilities["STANCE_CHANGE"] = 176] = "STANCE_CHANGE"; - Abilities[Abilities["GALE_WINGS"] = 177] = "GALE_WINGS"; - Abilities[Abilities["MEGA_LAUNCHER"] = 178] = "MEGA_LAUNCHER"; - Abilities[Abilities["GRASS_PELT"] = 179] = "GRASS_PELT"; - Abilities[Abilities["SYMBIOSIS"] = 180] = "SYMBIOSIS"; - Abilities[Abilities["TOUGH_CLAWS"] = 181] = "TOUGH_CLAWS"; - Abilities[Abilities["PIXILATE"] = 182] = "PIXILATE"; - Abilities[Abilities["GOOEY"] = 183] = "GOOEY"; - Abilities[Abilities["AERILATE"] = 184] = "AERILATE"; - Abilities[Abilities["PARENTAL_BOND"] = 185] = "PARENTAL_BOND"; - Abilities[Abilities["DARK_AURA"] = 186] = "DARK_AURA"; - Abilities[Abilities["FAIRY_AURA"] = 187] = "FAIRY_AURA"; - Abilities[Abilities["AURA_BREAK"] = 188] = "AURA_BREAK"; - Abilities[Abilities["PRIMORDIAL_SEA"] = 189] = "PRIMORDIAL_SEA"; - Abilities[Abilities["DESOLATE_LAND"] = 190] = "DESOLATE_LAND"; - Abilities[Abilities["DELTA_STREAM"] = 191] = "DELTA_STREAM"; - Abilities[Abilities["STAMINA"] = 192] = "STAMINA"; - Abilities[Abilities["WIMP_OUT"] = 193] = "WIMP_OUT"; - Abilities[Abilities["EMERGENCY_EXIT"] = 194] = "EMERGENCY_EXIT"; - Abilities[Abilities["WATER_COMPACTION"] = 195] = "WATER_COMPACTION"; - Abilities[Abilities["MERCILESS"] = 196] = "MERCILESS"; - Abilities[Abilities["SHIELDS_DOWN"] = 197] = "SHIELDS_DOWN"; - Abilities[Abilities["STAKEOUT"] = 198] = "STAKEOUT"; - Abilities[Abilities["WATER_BUBBLE"] = 199] = "WATER_BUBBLE"; - Abilities[Abilities["STEELWORKER"] = 200] = "STEELWORKER"; - Abilities[Abilities["BERSERK"] = 201] = "BERSERK"; - Abilities[Abilities["SLUSH_RUSH"] = 202] = "SLUSH_RUSH"; - Abilities[Abilities["LONG_REACH"] = 203] = "LONG_REACH"; - Abilities[Abilities["LIQUID_VOICE"] = 204] = "LIQUID_VOICE"; - Abilities[Abilities["TRIAGE"] = 205] = "TRIAGE"; - Abilities[Abilities["GALVANIZE"] = 206] = "GALVANIZE"; - Abilities[Abilities["SURGE_SURFER"] = 207] = "SURGE_SURFER"; - Abilities[Abilities["SCHOOLING"] = 208] = "SCHOOLING"; - Abilities[Abilities["DISGUISE"] = 209] = "DISGUISE"; - Abilities[Abilities["BATTLE_BOND"] = 210] = "BATTLE_BOND"; - Abilities[Abilities["POWER_CONSTRUCT"] = 211] = "POWER_CONSTRUCT"; - Abilities[Abilities["CORROSION"] = 212] = "CORROSION"; - Abilities[Abilities["COMATOSE"] = 213] = "COMATOSE"; - Abilities[Abilities["QUEENLY_MAJESTY"] = 214] = "QUEENLY_MAJESTY"; - Abilities[Abilities["INNARDS_OUT"] = 215] = "INNARDS_OUT"; - Abilities[Abilities["DANCER"] = 216] = "DANCER"; - Abilities[Abilities["BATTERY"] = 217] = "BATTERY"; - Abilities[Abilities["FLUFFY"] = 218] = "FLUFFY"; - Abilities[Abilities["DAZZLING"] = 219] = "DAZZLING"; - Abilities[Abilities["SOUL_HEART"] = 220] = "SOUL_HEART"; - Abilities[Abilities["TANGLING_HAIR"] = 221] = "TANGLING_HAIR"; - Abilities[Abilities["RECEIVER"] = 222] = "RECEIVER"; - Abilities[Abilities["POWER_OF_ALCHEMY"] = 223] = "POWER_OF_ALCHEMY"; - Abilities[Abilities["BEAST_BOOST"] = 224] = "BEAST_BOOST"; - Abilities[Abilities["RKS_SYSTEM"] = 225] = "RKS_SYSTEM"; - Abilities[Abilities["ELECTRIC_SURGE"] = 226] = "ELECTRIC_SURGE"; - Abilities[Abilities["PSYCHIC_SURGE"] = 227] = "PSYCHIC_SURGE"; - Abilities[Abilities["MISTY_SURGE"] = 228] = "MISTY_SURGE"; - Abilities[Abilities["GRASSY_SURGE"] = 229] = "GRASSY_SURGE"; - Abilities[Abilities["FULL_METAL_BODY"] = 230] = "FULL_METAL_BODY"; - Abilities[Abilities["SHADOW_SHIELD"] = 231] = "SHADOW_SHIELD"; - Abilities[Abilities["PRISM_ARMOR"] = 232] = "PRISM_ARMOR"; - Abilities[Abilities["NEUROFORCE"] = 233] = "NEUROFORCE"; - Abilities[Abilities["INTREPID_SWORD"] = 234] = "INTREPID_SWORD"; - Abilities[Abilities["DAUNTLESS_SHIELD"] = 235] = "DAUNTLESS_SHIELD"; - Abilities[Abilities["LIBERO"] = 236] = "LIBERO"; - Abilities[Abilities["BALL_FETCH"] = 237] = "BALL_FETCH"; - Abilities[Abilities["COTTON_DOWN"] = 238] = "COTTON_DOWN"; - Abilities[Abilities["PROPELLER_TAIL"] = 239] = "PROPELLER_TAIL"; - Abilities[Abilities["MIRROR_ARMOR"] = 240] = "MIRROR_ARMOR"; - Abilities[Abilities["GULP_MISSILE"] = 241] = "GULP_MISSILE"; - Abilities[Abilities["STALWART"] = 242] = "STALWART"; - Abilities[Abilities["STEAM_ENGINE"] = 243] = "STEAM_ENGINE"; - Abilities[Abilities["PUNK_ROCK"] = 244] = "PUNK_ROCK"; - Abilities[Abilities["SAND_SPIT"] = 245] = "SAND_SPIT"; - Abilities[Abilities["ICE_SCALES"] = 246] = "ICE_SCALES"; - Abilities[Abilities["RIPEN"] = 247] = "RIPEN"; - Abilities[Abilities["ICE_FACE"] = 248] = "ICE_FACE"; - Abilities[Abilities["POWER_SPOT"] = 249] = "POWER_SPOT"; - Abilities[Abilities["MIMICRY"] = 250] = "MIMICRY"; - Abilities[Abilities["SCREEN_CLEANER"] = 251] = "SCREEN_CLEANER"; - Abilities[Abilities["STEELY_SPIRIT"] = 252] = "STEELY_SPIRIT"; - Abilities[Abilities["PERISH_BODY"] = 253] = "PERISH_BODY"; - Abilities[Abilities["WANDERING_SPIRIT"] = 254] = "WANDERING_SPIRIT"; - Abilities[Abilities["GORILLA_TACTICS"] = 255] = "GORILLA_TACTICS"; - Abilities[Abilities["NEUTRALIZING_GAS"] = 256] = "NEUTRALIZING_GAS"; - Abilities[Abilities["PASTEL_VEIL"] = 257] = "PASTEL_VEIL"; - Abilities[Abilities["HUNGER_SWITCH"] = 258] = "HUNGER_SWITCH"; - Abilities[Abilities["QUICK_DRAW"] = 259] = "QUICK_DRAW"; - Abilities[Abilities["UNSEEN_FIST"] = 260] = "UNSEEN_FIST"; - Abilities[Abilities["CURIOUS_MEDICINE"] = 261] = "CURIOUS_MEDICINE"; - Abilities[Abilities["TRANSISTOR"] = 262] = "TRANSISTOR"; - Abilities[Abilities["DRAGONS_MAW"] = 263] = "DRAGONS_MAW"; - Abilities[Abilities["CHILLING_NEIGH"] = 264] = "CHILLING_NEIGH"; - Abilities[Abilities["GRIM_NEIGH"] = 265] = "GRIM_NEIGH"; - Abilities[Abilities["AS_ONE_GLASTRIER"] = 266] = "AS_ONE_GLASTRIER"; - Abilities[Abilities["AS_ONE_SPECTRIER"] = 267] = "AS_ONE_SPECTRIER"; - Abilities[Abilities["LINGERING_AROMA"] = 268] = "LINGERING_AROMA"; - Abilities[Abilities["SEED_SOWER"] = 269] = "SEED_SOWER"; - Abilities[Abilities["THERMAL_EXCHANGE"] = 270] = "THERMAL_EXCHANGE"; - Abilities[Abilities["ANGER_SHELL"] = 271] = "ANGER_SHELL"; - Abilities[Abilities["PURIFYING_SALT"] = 272] = "PURIFYING_SALT"; - Abilities[Abilities["WELL_BAKED_BODY"] = 273] = "WELL_BAKED_BODY"; - Abilities[Abilities["WIND_RIDER"] = 274] = "WIND_RIDER"; - Abilities[Abilities["GUARD_DOG"] = 275] = "GUARD_DOG"; - Abilities[Abilities["ROCKY_PAYLOAD"] = 276] = "ROCKY_PAYLOAD"; - Abilities[Abilities["WIND_POWER"] = 277] = "WIND_POWER"; - Abilities[Abilities["ZERO_TO_HERO"] = 278] = "ZERO_TO_HERO"; - Abilities[Abilities["COMMANDER"] = 279] = "COMMANDER"; - Abilities[Abilities["ELECTROMORPHOSIS"] = 280] = "ELECTROMORPHOSIS"; - Abilities[Abilities["PROTOSYNTHESIS"] = 281] = "PROTOSYNTHESIS"; - Abilities[Abilities["QUARK_DRIVE"] = 282] = "QUARK_DRIVE"; - Abilities[Abilities["GOOD_AS_GOLD"] = 283] = "GOOD_AS_GOLD"; - Abilities[Abilities["VESSEL_OF_RUIN"] = 284] = "VESSEL_OF_RUIN"; - Abilities[Abilities["SWORD_OF_RUIN"] = 285] = "SWORD_OF_RUIN"; - Abilities[Abilities["TABLETS_OF_RUIN"] = 286] = "TABLETS_OF_RUIN"; - Abilities[Abilities["BEADS_OF_RUIN"] = 287] = "BEADS_OF_RUIN"; - Abilities[Abilities["ORICHALCUM_PULSE"] = 288] = "ORICHALCUM_PULSE"; - Abilities[Abilities["HADRON_ENGINE"] = 289] = "HADRON_ENGINE"; - Abilities[Abilities["OPPORTUNIST"] = 290] = "OPPORTUNIST"; - Abilities[Abilities["CUD_CHEW"] = 291] = "CUD_CHEW"; - Abilities[Abilities["SHARPNESS"] = 292] = "SHARPNESS"; - Abilities[Abilities["SUPREME_OVERLORD"] = 293] = "SUPREME_OVERLORD"; - Abilities[Abilities["COSTAR"] = 294] = "COSTAR"; - Abilities[Abilities["TOXIC_DEBRIS"] = 295] = "TOXIC_DEBRIS"; - Abilities[Abilities["ARMOR_TAIL"] = 296] = "ARMOR_TAIL"; - Abilities[Abilities["EARTH_EATER"] = 297] = "EARTH_EATER"; - Abilities[Abilities["MYCELIUM_MIGHT"] = 298] = "MYCELIUM_MIGHT"; - Abilities[Abilities["MINDS_EYE"] = 299] = "MINDS_EYE"; - Abilities[Abilities["SUPERSWEET_SYRUP"] = 300] = "SUPERSWEET_SYRUP"; - Abilities[Abilities["HOSPITALITY"] = 301] = "HOSPITALITY"; - Abilities[Abilities["TOXIC_CHAIN"] = 302] = "TOXIC_CHAIN"; - Abilities[Abilities["EMBODY_ASPECT_TEAL"] = 303] = "EMBODY_ASPECT_TEAL"; - Abilities[Abilities["EMBODY_ASPECT_WELLSPRING"] = 304] = "EMBODY_ASPECT_WELLSPRING"; - Abilities[Abilities["EMBODY_ASPECT_HEARTHFLAME"] = 305] = "EMBODY_ASPECT_HEARTHFLAME"; - Abilities[Abilities["EMBODY_ASPECT_CORNERSTONE"] = 306] = "EMBODY_ASPECT_CORNERSTONE"; - Abilities[Abilities["TERA_SHIFT"] = 307] = "TERA_SHIFT"; - Abilities[Abilities["TERA_SHELL"] = 308] = "TERA_SHELL"; - Abilities[Abilities["TERAFORM_ZERO"] = 309] = "TERAFORM_ZERO"; - Abilities[Abilities["POISON_PUPPETEER"] = 310] = "POISON_PUPPETEER"; -})(Abilities || (Abilities = {})); -let Nature; -(function (Nature) { - Nature[Nature["HARDY"] = 0] = "HARDY"; - Nature[Nature["LONELY"] = 1] = "LONELY"; - Nature[Nature["BRAVE"] = 2] = "BRAVE"; - Nature[Nature["ADAMANT"] = 3] = "ADAMANT"; - Nature[Nature["NAUGHTY"] = 4] = "NAUGHTY"; - Nature[Nature["BOLD"] = 5] = "BOLD"; - Nature[Nature["DOCILE"] = 6] = "DOCILE"; - Nature[Nature["RELAXED"] = 7] = "RELAXED"; - Nature[Nature["IMPISH"] = 8] = "IMPISH"; - Nature[Nature["LAX"] = 9] = "LAX"; - Nature[Nature["TIMID"] = 10] = "TIMID"; - Nature[Nature["HASTY"] = 11] = "HASTY"; - Nature[Nature["SERIOUS"] = 12] = "SERIOUS"; - Nature[Nature["JOLLY"] = 13] = "JOLLY"; - Nature[Nature["NAIVE"] = 14] = "NAIVE"; - Nature[Nature["MODEST"] = 15] = "MODEST"; - Nature[Nature["MILD"] = 16] = "MILD"; - Nature[Nature["QUIET"] = 17] = "QUIET"; - Nature[Nature["BASHFUL"] = 18] = "BASHFUL"; - Nature[Nature["RASH"] = 19] = "RASH"; - Nature[Nature["CALM"] = 20] = "CALM"; - Nature[Nature["GENTLE"] = 21] = "GENTLE"; - Nature[Nature["SASSY"] = 22] = "SASSY"; - Nature[Nature["CAREFUL"] = 23] = "CAREFUL"; - Nature[Nature["QUIRKY"] = 24] = "QUIRKY"; -})(Nature || (Nature = {})); -let WeatherType; -(function (WeatherType) { - WeatherType[WeatherType["NONE"] = 0] = "NONE"; - WeatherType[WeatherType["SUNNY"] = 1] = "SUNNY"; - WeatherType[WeatherType["RAIN"] = 2] = "RAIN"; - WeatherType[WeatherType["SANDSTORM"] = 3] = "SANDSTORM"; - WeatherType[WeatherType["HAIL"] = 4] = "HAIL"; - WeatherType[WeatherType["SNOW"] = 5] = "SNOW"; - WeatherType[WeatherType["FOG"] = 6] = "FOG"; - WeatherType[WeatherType["HEAVY_RAIN"] = 7] = "HEAVY_RAIN"; - WeatherType[WeatherType["HARSH_SUN"] = 8] = "HARSH_SUN"; - WeatherType[WeatherType["STRONG_WINDS"] = 9] = "STRONG_WINDS"; -})(WeatherType || (WeatherType = {})); -function getPokemonSpriteURL(id) { - // Construct the sprite URL based on the Pokemon ID - const spriteURL = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`; - return spriteURL; -} -// Function to get Pokémon type -async function getPokeType(id) { - try { - const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`); - const data = await response.json(); - const types = data.types.map(type => type.type.name); - return types; - } catch (error) { - console.error('Error fetching Pokémon type:', error); - return null; - } -} - -// Function to get type effectiveness -async function getTypeEffectiveness(type) { - try { - const response = await fetch(`https://pokeapi.co/api/v2/type/${type}`); - const data = await response.json(); - return data.damage_relations; - } catch (error) { - console.error(`Error fetching type effectiveness for ${type}:`, error); - return null; - } -} - -// Function to calculate weaknesses, resistances, and immunities -async function calculateTypeEffectiveness(types) { - const typeEffectiveness = await Promise.all(types.map(getTypeEffectiveness)); - if (typeEffectiveness.some(data => data === null)) { - return null; - } - - const weaknesses = new Set(); - const resistances = new Set(); - const immunities = new Set(); - - if (types.length === 1) { - const data = typeEffectiveness[0]; - data.double_damage_from.forEach(t => weaknesses.add(t.name)); - data.half_damage_from.forEach(t => resistances.add(t.name)); - data.no_damage_from.forEach(t => immunities.add(t.name)); - } else if (types.length === 2) { - const [type1, type2] = types; - const type1Effectiveness = typeEffectiveness[0]; - const type2Effectiveness = typeEffectiveness[1]; - - // Calculate weaknesses - type1Effectiveness.double_damage_from.forEach(t => { - if (!type2Effectiveness.half_damage_from.some(r => r.name === t.name)) { - weaknesses.add(t.name) - } - }); - type2Effectiveness.double_damage_from.forEach(t => { - if (!type1Effectiveness.half_damage_from.some(r => r.name === t.name)) { - weaknesses.add(t.name) - } - }); - - // Calculate resistances - type1Effectiveness.half_damage_from.forEach(t => { - if (!type2Effectiveness.double_damage_from.some(r => r.name === t.name)) { - resistances.add(t.name) - } - }); - - type2Effectiveness.half_damage_from.forEach(t => { - if (!type1Effectiveness.double_damage_from.some(r => r.name === t.name)) { - resistances.add(t.name) - } - }); - - // Calculate immunities - type1Effectiveness.no_damage_from.forEach(t => immunities.add(t.name)) - type2Effectiveness.no_damage_from.forEach(t => immunities.add(t.name)) - - immunities.forEach(immunity => { - weaknesses.delete(immunity); - resistances.delete(immunity); - }) - } - - return { weaknesses, resistances, immunities }; -} - - -// Example usage -async function getPokemonTypeEffectiveness(id) { - const types = await getPokeType(id); - if (types) { - const { weaknesses, resistances, immunities } = await calculateTypeEffectiveness(types); - return { - 'weaknesses': weaknesses, - 'resistances': resistances, - 'immunities': immunities - } - } - return {} -} - -function updateDiv(pokemon, weather, message) { - browserApi.tabs.query({ active: true, currentWindow: true }, function (tabs) { - browserApi.tabs.sendMessage(tabs[0].id, { type: message, pokemon: pokemon, weather: weather, slotId: slotId }, (response) => { - if (response && response.success) { - console.log('Div updated successfully'); - } else { - console.error('Failed to update div'); - } - }); - }); -} - - -function convertPokemonId(pokemonId) { - const conversionList = { - 2019: 10091, - 2020: 10092, - 2026: 10100, - 2027: 10101, - 2028: 10102, - 2037: 10103, - 2038: 10104, - 2050: 10105, - 2051: 10106, - 2052: 10107, - 2053: 10108, - 2074: 10109, - 2075: 10110, - 2076: 10111, - 2088: 10112, - 2089: 10113, - 2103: 10114, - 2105: 10115, - 2670: 10061, - 4052: 10162, - 4077: 10163, - 4078: 10164, - 4079: 10165, - 4080: 10166, - 4083: 10167, - 4110: 10168, - 4122: 10169, - 4144: 10170, - 4145: 10171, - 4146: 10172, - 4199: 10173, - 4222: 10174, - 4263: 10175, - 4264: 10176, - 4554: 10177, - 4555: 10178, - 4562: 10179, - 4618: 10180, - 6058: 10229, - 6059: 10230, - 6100: 10231, - 6101: 10232, - 6157: 10233, - 6211: 10234, - 6215: 10235, - 6503: 10236, - 6549: 10237, - 6570: 10238, - 6571: 10239, - 6628: 10240, - 6705: 10241, - 6706: 10242, - 6713: 10243, - 6724: 10244, - 8128: 10252, - 8194: 10253, - 8901: 10272 - } - if (pokemonId in conversionList) { - return conversionList[pokemonId] - } else { - return pokemonId - } -} - -function mapPartyToPokemonArray(party) { - return party.map(({ species, abilityIndex, nature, ivs }) => ({ species, abilityIndex, nature, ivs })) -} - -// message can be either "UPDATE_ALLIES_DIV" or "UPDATE_ENEMIES_DIV" -function appendPokemonArrayToDiv(pokemonArray, arena, message) { - let frontendPokemonArray = [] - pokemonArray.forEach((pokemon) => { - const pokemonId = convertPokemonId(pokemon.species) - let weather = {} - if (arena.weather && arena.weather.weatherType) { - weather = { - 'type': WeatherType[arena.weather.weatherType], - 'turnsLeft': arena.weather.turnsLeft || 0 - } - } - getPokemonTypeEffectiveness(pokemonId).then((typeEffectiveness) => { - console.log("Got pokemon", pokemonId, "type effectiveness", typeEffectiveness) - frontendPokemonArray.push({ - 'id': pokemon.species, - 'typeEffectiveness': { - 'weaknesses': Array.from(typeEffectiveness.weaknesses), - 'resistances': Array.from(typeEffectiveness.resistances), - 'immunities': Array.from(typeEffectiveness.immunities) - }, - 'ivs': pokemon.ivs, - 'ability': Abilities[pokemon.abilityIndex], - 'nature': Nature[pokemon.nature] - }) - updateDiv(frontendPokemonArray, weather, message) - }) - }) -} - -// browserApi.runtime.onMessage.addListener(function(request, sender, sendResponse) { -// // Happens when loading a savegame or continuing an old run -// if (request.type == 'BG_GET_SAVEDATA') { -// const savedata = request.data -// slotId = request.slotId -// console.log("Received save data", savedata) -// appendPokemonArrayToDiv(mapPartyToPokemonArray(savedata.enemyParty), savedata.arena, "UPDATE_ENEMIES_DIV") -// appendPokemonArrayToDiv(mapPartyToPokemonArray(savedata.party), savedata.arena, "UPDATE_ALLIES_DIV") -// } -// }); - -browserApi.runtime.onMessage.addListener((request, sender, sendResponse) => { +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === "fetchFusionImageHtml") { - const fusionUrl = `https://if.daena.me/find/?head=${request.pokemonId}&body=${request.fusionId}`; + const { fusionId, pokemonId } = request; - fetch(fusionUrl, { method: 'GET', redirect: 'follow' }) - .then(response => { - if (response.status === 307 || response.status === 200) { - return fetch(response.url).then(res => res.text()); - } else { - throw new Error(`Unexpected status code: ${response.status}`); - } - }) + fetch(`https://if.daena.me/find/?head=${fusionId}&body=${pokemonId}`) + .then(response => response.text()) .then(html => { - sendResponse({ success: true, html: html }); + sendResponse({ success: true, html }); }) .catch(error => { - console.error("Fetch error:", error); - sendResponse({ success: false, error: error.message }); + console.error('Error fetching fusion image HTML:', error); + sendResponse({ success: false, error }); }); - // Return true to indicate you wish to send a response asynchronously - return true; + return true; // Will respond asynchronously + } else if (request.action === "fetchImage") { + fetch(request.url) + .then(response => response.blob()) + .then(blob => { + const reader = new FileReader(); + reader.onloadend = () => { + sendResponse({ success: true, dataUrl: reader.result }); + }; + reader.onerror = () => { + sendResponse({ success: false, error: 'Failed to read blob' }); + }; + reader.readAsDataURL(blob); + }) + .catch(error => { + console.error('Error fetching image:', error); + sendResponse({ success: false, error }); + }); + + return true; // Will respond asynchronously } }); - - - - - -// browserApi.webRequest.onBeforeRequest.addListener( -// function(details) { -// if (details.method === 'POST') { -// try { -// let sessionData = JSON.parse(new TextDecoder().decode(details.requestBody.raw[0].bytes)) -// console.log("POST Session data:", sessionData) -// if (details.url.includes("updateall")) sessionData = sessionData.session -// appendPokemonArrayToDiv(mapPartyToPokemonArray(sessionData.enemyParty), sessionData.arena, "UPDATE_ENEMIES_DIV") -// appendPokemonArrayToDiv(mapPartyToPokemonArray(sessionData.party), sessionData.arena, "UPDATE_ALLIES_DIV") -// } catch (e) { -// console.error("Error while intercepting web request: ", e) -// } -// } -// }, -// { -// urls: ['https://api.pokerogue.net/savedata/update?datatype=1*', 'https://api.pokerogue.net/savedata/updateall'] -// }, -// ["requestBody"] -// ) \ No newline at end of file diff --git a/content/content.js b/content/content.js index f1a1b8b..630a3a7 100644 --- a/content/content.js +++ b/content/content.js @@ -23,8 +23,9 @@ function initUtilities(e) { Utils.init(); Utils.addEventListener('isReadyChange', () => { if (Utils.isReady) { + //Utils.LocalStorage.clearImageCache(); console.log("All Scripts Loaded!") - touchControlListener(); + //touchControlListener(); extensionSettingsListener(); } else { console.log("Error Loading Scripts :(") @@ -339,20 +340,25 @@ function ivComparison(pokeIv, dexIv) { return returnHTML; } -function getPokemonIcon(pokemon, divId) { +const imageCache = {}; + +async function getPokemonIcon(pokemon, divId) { + const cacheKey = pokemon.fusionId ? `${pokemon.name}-${pokemon.fusionId}` : pokemon.name; + console.time(`getPokemonIcon_${cacheKey}`); // Start the timer + const canvas = document.getElementById(`pokemon-icon_${divId}`); - if(canvas) { + if (canvas) { const ctx = canvas.getContext('2d'); const parent = canvas.parentElement; const image1 = new Image(); const image2 = new Image(); const fusionImage = new Image(); - const loadImage = (image, src) => { + const loadImageFromBlobUrl = (image, blobUrl) => { return new Promise((resolve, reject) => { image.onload = () => resolve(image); - image.onerror = () => reject(new Error(`Failed to load image from ${src}`)); - image.src = src; + image.onerror = reject; + image.src = blobUrl; }); }; @@ -362,11 +368,9 @@ function getPokemonIcon(pokemon, divId) { const parentHeight = parent.clientHeight; const canvasWidth = parentHeight * (width / height); - // Set canvas dimensions based on the parent's height canvas.width = canvasWidth; canvas.height = parentHeight; - // Draw the full image ctx.drawImage(image, 0, 0, width, height, 0, 0, canvasWidth, parentHeight); }; @@ -376,66 +380,122 @@ function getPokemonIcon(pokemon, divId) { const parentHeight = parent.clientHeight; const canvasWidth = parentHeight * (width / height); - // Set canvas dimensions based on the parent's height canvas.width = canvasWidth; canvas.height = parentHeight; - // Draw the top half of the first image ctx.drawImage(image1, 0, 0, width, height / 2, 0, 0, canvasWidth, parentHeight / 2); - - // Draw the bottom half of the second image ctx.drawImage(image2, 0, height / 2, width, height / 2, 0, parentHeight / 2, canvasWidth, parentHeight / 2); }; + const fetchImageAndCache = (url, cacheKey, image) => { + return new Promise((resolve, reject) => { + chrome.runtime.sendMessage({ + action: "fetchImage", + url: url + }, response => { + if (response.success) { + const blobUrl = response.dataUrl; + imageCache[cacheKey] = blobUrl; // Save Blob URL to memory cache + Utils.LocalStorage.saveImageToCache(cacheKey, blobUrl); // Save to local storage + loadImageFromBlobUrl(image, blobUrl).then(resolve).catch(reject); + } else { + reject(response.error); + } + }); + }); + }; + const image1Src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; const image2Src = pokemon.fusionId ? `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.fusionId}.png` : null; - if (pokemon.fusionId) { - let fusionName = Utils.PokeMapper.capitalizeFirstLetter((Utils.PokeMapper.I2P[pokemon.fusionId])); - let pokeName = Utils.PokeMapper.capitalizeFirstLetter((Utils.PokeMapper.I2P[pokemon.id])); - chrome.runtime.sendMessage({ - action: "fetchFusionImageHtml", - fusionId: fusionName, - pokemonId: pokeName - }, response => { - if (response.success) { - const parser = new DOMParser(); - console.log(response.html); - const doc = parser.parseFromString(response.html, 'text/html'); - const figure = doc.querySelector('figure.sprite.sprite-variant-main'); - console.log(figure); - if (figure) { - const img = figure.querySelector('img'); - if (img) { - loadImage(fusionImage, img.src) - .then(() => drawSingleImage(fusionImage)) - .catch(() => { - // Fallback to combined images method if fusion image fails to load - Promise.all([ - loadImage(image1, image1Src), - loadImage(image2, image2Src) - ]) - .then(drawCombinedImages) - .catch(error => console.error(error)); + const cachedImage = imageCache[cacheKey] || Utils.LocalStorage.getImageFromCache(cacheKey); + + if (cachedImage) { + console.log('Using cached image'); + const blobUrl = cachedImage; + imageCache[cacheKey] = blobUrl; // Save to memory cache if loaded from local storage + loadImageFromBlobUrl(image1, blobUrl).then(() => { + if (pokemon.fusionId) { + loadImageFromBlobUrl(image2, blobUrl).then(drawCombinedImages).catch(error => console.error(error)); + } else { + drawSingleImage(image1); + } + console.timeEnd(`getPokemonIcon_${cacheKey}`); // End the timer + }).catch(error => console.error(error)); + } else { + if (pokemon.fusionId) { + const fusionName = Utils.PokeMapper.capitalizeFirstLetter(Utils.PokeMapper.I2P[pokemon.fusionId]); + const pokeName = Utils.PokeMapper.capitalizeFirstLetter(Utils.PokeMapper.I2P[pokemon.id]); + + chrome.runtime.sendMessage({ + action: "fetchFusionImageHtml", + fusionId: fusionName, + pokemonId: pokeName + }, response => { + if (response.success) { + const parser = new DOMParser(); + const doc = parser.parseFromString(response.html, 'text/html'); + const figure = doc.querySelector('figure.sprite.sprite-variant-main'); + if (figure) { + const img = figure.querySelector('img'); + if (img) { + chrome.runtime.sendMessage({ + action: "fetchImage", + url: img.src + }, imageResponse => { + if (imageResponse.success) { + const blobUrl = imageResponse.dataUrl; + imageCache[cacheKey] = blobUrl; // Save Blob URL to memory cache + Utils.LocalStorage.saveImageToCache(cacheKey, blobUrl); // Save to local storage + loadImageFromBlobUrl(fusionImage, blobUrl) + .then(() => { + drawSingleImage(fusionImage); + console.timeEnd(`getPokemonIcon_${cacheKey}`); // End the timer + }) + .catch(error => console.error(error)); + } else { + console.error('Failed to fetch fusion image:', imageResponse.error); + fallbackToSeparateImages(); + } }); - return; + return; + } } } - } - // Fallback to combined images method if fusion image not found - Promise.all([ - loadImage(image1, image1Src), - loadImage(image2, image2Src) - ]) - .then(drawCombinedImages) + fallbackToSeparateImages(); + }); + } else { + fetchImageAndCache(image1Src, cacheKey, image1) + .then(() => { + drawSingleImage(image1); + console.timeEnd(`getPokemonIcon_${cacheKey}`); // End the timer + }) .catch(error => console.error(error)); - }); - } else { - // If fusionId is null, just load and display the single image - loadImage(image1, image1Src) - .then(drawSingleImage) - .catch(error => console.error(error)); + } } + + const fallbackToSeparateImages = () => { + Promise.all([ + fetchImageAndCache(image1Src, `${pokemon.name}-1`, image1), + fetchImageAndCache(image2Src, `${pokemon.name}-2`, image2) + ]) + .then(drawCombinedImages) + .then(() => { + // Combine the images into a single canvas and cache it + const combinedCanvas = document.createElement('canvas'); + combinedCanvas.width = canvas.width; + combinedCanvas.height = canvas.height; + const combinedCtx = combinedCanvas.getContext('2d'); + combinedCtx.drawImage(canvas, 0, 0); + const combinedDataUrl = combinedCanvas.toDataURL(); + + imageCache[cacheKey] = combinedDataUrl; // Save combined image to memory cache + Utils.LocalStorage.saveImageToCache(cacheKey, combinedDataUrl); // Save combined image to local storage + + console.timeEnd(`getPokemonIcon_${cacheKey}`); // End the timer + }) + .catch(error => console.error(error)); + }; } console.log(pokemon); } @@ -445,9 +505,6 @@ function getPokemonIcon(pokemon, divId) { - - - async function createPokemonCardDiv_minified(cardId, pokemon) { let savedData = Utils.LocalStorage.getPlayerData(); let dexData = savedData["dexData"]; @@ -472,6 +529,9 @@ async function createPokemonCardDiv_minified(cardId, pokemon) {
${pokemon.name}
+
+ +
Ability: ${pokemon.ability.name} ${createTooltipDiv(pokemon.ability.description)} diff --git a/content/util_classes/localStorage.util.js b/content/util_classes/localStorage.util.js index b7a84ca..93e06e5 100644 --- a/content/util_classes/localStorage.util.js +++ b/content/util_classes/localStorage.util.js @@ -24,6 +24,27 @@ class LocalStorageClass { }, 1000) } + saveImageToCache(key, imageData) { + try { + localStorage.setItem(`img_cache_${key}`, imageData); + } catch (e) { + console.error("Failed to save image to cache", e); + } + } + + getImageFromCache(key) { + return localStorage.getItem(`img_cache_${key}`); + } + + clearImageCache() { + const keys = Object.keys(localStorage); + keys.forEach(key => { + if (key.startsWith('img_cache_')) { + localStorage.removeItem(key); + } + }); + } + setSessionData(){ let currentSessionData = {} for (let key in localStorage) { diff --git a/inject.js b/inject.js index d5f8af6..0b34060 100644 --- a/inject.js +++ b/inject.js @@ -10,15 +10,3 @@ s.onload = function () { }; (document.head || document.documentElement).appendChild(s); -// receive message from injected script -window.addEventListener('message', function (e) { - if (e.data.type === 'GET_SAVEDATA') { - browserApi.runtime.sendMessage({ type: 'BG_GET_SAVEDATA', data: e.data.data, slotId: e.data.slotId }, function(response) { - if (response && response.success) { - console.log('Successfully updated game info'); - } else { - console.error('Failed to update game info'); - } - }); - } -}); \ No newline at end of file diff --git a/injected.js b/injected.js index 4dd20f6..bc1354e 100644 --- a/injected.js +++ b/injected.js @@ -22,24 +22,24 @@ }; })(XMLHttpRequest); -const { fetch: origFetch } = window; -window.fetch = async (...args) => { - const response = await origFetch(...args); - if (!response.url.includes('api.pokerogue.net/savedata/session?slot') && - !response.url.includes('api.pokerogue.net/savedata/updateall')) return response - - let sessionSlotRegex = /.*\/session\?slot=(\d+).*/ - let slotId = -1 - if (sessionSlotRegex.test(response.url)){ - slotId = sessionSlotRegex.exec(response.url)[1] - } - response - .clone() - .json() // maybe json(), text(), blob() - .then(data => { - window.postMessage({ type: 'GET_SAVEDATA', data: data, slotId: slotId }, '*'); // send to content script - //window.postMessage({ type: 'fetch', data: URL.createObjectURL(data) }, '*'); // if a big media file, can createObjectURL before send to content script - }) - .catch(err => console.error(err)); - return response; -}; \ No newline at end of file +// const { fetch: origFetch } = window; +// window.fetch = async (...args) => { +// const response = await origFetch(...args); +// if (!response.url.includes('api.pokerogue.net/savedata/session?slot') && +// !response.url.includes('api.pokerogue.net/savedata/updateall')) return response +// +// let sessionSlotRegex = /.*\/session\?slot=(\d+).*/ +// let slotId = -1 +// if (sessionSlotRegex.test(response.url)){ +// slotId = sessionSlotRegex.exec(response.url)[1] +// } +// response +// .clone() +// .json() // maybe json(), text(), blob() +// .then(data => { +// window.postMessage({ type: 'GET_SAVEDATA', data: data, slotId: slotId }, '*'); // send to content script +// //window.postMessage({ type: 'fetch', data: URL.createObjectURL(data) }, '*'); // if a big media file, can createObjectURL before send to content script +// }) +// .catch(err => console.error(err)); +// return response; +// }; \ No newline at end of file diff --git a/manifest.json b/manifest.json index fcec742..f57ec1e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,45 +1,48 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "Rogue Dex", "version": "2.6", "permissions": [ "activeTab", "webRequest", "storage", + "https://if.daena.me/*", + "https://cdn.daena.me/*" + ], + "host_permissions": [ "https://pokerogue.net/*", - "https://api.pokerogue.net/*" + "https://api.pokerogue.net/*", + "https://if.daena.me/*", + "https://cdn.daena.me/*" ], - "browser_specific_settings": { - "gecko": { - "id": "{46029ed0-cb54-4130-8105-fcbbed40adc1}" - } - }, "options_page": "options/options.html", "options_ui": { "page": "options/options.html", "open_in_tab": false }, - "browser_action": { - "default_popup": "options/options.html", - "default_icon": "./RogueDex.png", - "default_title": "RogueDex" + "action": { + "default_popup": "options/options.html" }, "background": { - "scripts": ["background.js"], - "persistent": true + "service_worker": "background.js" }, "content_scripts": [ { - "matches": ["https://api.pokerogue.net/*", "https://pokerogue.net/*"], - "js" : [ + "matches": [ + "https://api.pokerogue.net/*", + "https://pokerogue.net/*" + ], + "js": [ "inject.js" ], "run_at": "document_start", "all_frames": true }, { - "matches": ["https://pokerogue.net/*"], - "js" : [ + "matches": [ + "https://pokerogue.net/*" + ], + "js": [ "content/utils.js", "libs/crypto-js.min.js", "content/maps/abilityMap.js", @@ -52,14 +55,24 @@ "content/content.js" ], "type": "module", - "css": ["styles.css"] + "css": [ + "styles.css" + ] } ], "web_accessible_resources": [ - "inject.js", - "injected.js", - "content/*", - "fonts/*", - "images/*" + { + "resources": [ + "inject.js", + "injected.js", + "content/*", + "images/*", + "fonts/*" + ], + "matches": [ + "" + ], + "extension_ids": [] + } ] -} \ No newline at end of file +} diff --git a/manifest_chrome.json b/manifest_chrome.json deleted file mode 100644 index 119140d..0000000 --- a/manifest_chrome.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "manifest_version": 3, - "name": "Rogue Dex", - "version": "2.6", - "permissions": [ - "activeTab", - "webRequest", - "storage" - ], - "host_permissions": [ - "https://pokerogue.net/*", - "https://api.pokerogue.net/*" - ], - "options_page": "options/options.html", - "options_ui": { - "page": "options/options.html", - "open_in_tab": false - }, - "action": { - "default_popup": "options/options.html" - }, - "background": { - "service_worker": "background.js" - }, - "content_scripts": [ - { - "matches": [ - "https://api.pokerogue.net/*", - "https://pokerogue.net/*" - ], - "js": [ - "inject.js" - ], - "run_at": "document_start", - "all_frames": true - }, - { - "matches": [ - "https://pokerogue.net/*" - ], - "js": [ - "content/utils.js", - "libs/crypto-js.min.js", - "content/maps/abilityMap.js", - "content/maps/natureMap.js", - "content/maps/Pokemon_To_Id.js", - "content/maps/weatherMap.js", - "content/maps/PokemonEvolutions.js", - "content/util_classes/pokemonMapper.util.js", - "content/util_classes/localStorage.util.js", - "content/content.js" - ], - "type": "module", - "css": [ - "styles.css" - ] - } - ], - "web_accessible_resources": [ - { - "resources": [ - "inject.js", - "injected.js", - "content/*", - "images/*", - "fonts/*" - ], - "matches": [ - "" - ], - "extension_ids": [] - } - ] -} diff --git a/manifest_firefox.json b/manifest_firefox.json index 6d9f080..fcec742 100644 --- a/manifest_firefox.json +++ b/manifest_firefox.json @@ -5,6 +5,7 @@ "permissions": [ "activeTab", "webRequest", + "storage", "https://pokerogue.net/*", "https://api.pokerogue.net/*" ], @@ -13,6 +14,16 @@ "id": "{46029ed0-cb54-4130-8105-fcbbed40adc1}" } }, + "options_page": "options/options.html", + "options_ui": { + "page": "options/options.html", + "open_in_tab": false + }, + "browser_action": { + "default_popup": "options/options.html", + "default_icon": "./RogueDex.png", + "default_title": "RogueDex" + }, "background": { "scripts": ["background.js"], "persistent": true @@ -29,11 +40,26 @@ { "matches": ["https://pokerogue.net/*"], "js" : [ - "content.js", - "libs/crypto-js.min.js" + "content/utils.js", + "libs/crypto-js.min.js", + "content/maps/abilityMap.js", + "content/maps/natureMap.js", + "content/maps/Pokemon_To_Id.js", + "content/maps/weatherMap.js", + "content/maps/PokemonEvolutions.js", + "content/util_classes/pokemonMapper.util.js", + "content/util_classes/localStorage.util.js", + "content/content.js" ], + "type": "module", "css": ["styles.css"] } ], - "web_accessible_resources": ["inject.js", "injected.js"] -} + "web_accessible_resources": [ + "inject.js", + "injected.js", + "content/*", + "fonts/*", + "images/*" + ] +} \ No newline at end of file diff --git a/options/imageInjector.js b/options/imageInjector.js index 6392295..f2658b6 100644 --- a/options/imageInjector.js +++ b/options/imageInjector.js @@ -23,7 +23,8 @@ export default class ImageInjector { parts.forEach(part => { const img = new Image(); - const url = this.browserApi.extension.getURL(`images/menu/${menuType}/${part}.png`); + let prefix = (this.browserApi === chrome) ? 'chrome-extension' : 'moz-extension'; + const url = `${prefix}://${this.extensionId}/images/menu/${menuType}/${part}.png`; img.src = url; this.preloadedImages[menuType][part] = img; }); diff --git a/options/options.css b/options/options.css index 9355479..1832655 100644 --- a/options/options.css +++ b/options/options.css @@ -186,6 +186,8 @@ body { font-family: 'PKMNems'; } + + .setting-label.focus { color: var(--yellow-main); /* Focused color */ text-shadow: 2px 2px 0 var(--red-sub); diff --git a/styles.css b/styles.css index bc2c84e..eaa5640 100644 --- a/styles.css +++ b/styles.css @@ -134,6 +134,14 @@ visibility: visible; } +.image-overlay{ + position: absolute; + left: 20px; + top: -30px; + width: 96px; + height: 96px; +} + /* Slider settings */ @media screen and (-webkit-min-device-pixel-ratio:0) { input[type='range'] { From a047b90063ef5b5b72de3213d0001531e710dc26 Mon Sep 17 00:00:00 2001 From: Eruyome Date: Fri, 24 May 2024 11:03:07 +0200 Subject: [PATCH 12/78] Implemented a sidebar that shows all pokemon cards. Sidebar shows enemy and ally pokemon cards, all at the same time. Sidebar can be toggled on/off in the settings menu. Sidebar can be positioned left or right off the the game app, can be set in the options menu. Showing/hiding enemy or ally party in theoptions menu also affects what's being displayed in the sidebar. While the sidebar is enabled/shown, the overlay enemy and ally pokemon cards are hidden via css classes. --- RogueDex.png | Bin 1336 -> 3055 bytes content/content.js | 238 ++++++++++--- content/util_classes/localStorage.util.js | 10 +- manifest.json | 9 +- options/generateSettingsUI.js | 2 + options/optionsManager.js | 9 +- options/settingsTemplate.js | 12 + styles.css | 391 +++++++++++++++------- 8 files changed, 508 insertions(+), 163 deletions(-) diff --git a/RogueDex.png b/RogueDex.png index 74b3c550d8761c3046244c1e4d1b8ff9f2164d17..02b33ae28b885d286b983529643d2a497b4b2376 100644 GIT binary patch literal 3055 zcmcguX*ARg7yr*NcF{0K%9e`8G72e*v4Y%C|d zP0gwML@?jixT668Z_+sFPLLCw9e3N>9{@O^{}SjsHIjZ}6vXRT;mv$q@j*_0SODkb z?t_=}!Q#af<*vvnq+B?Bz!GbABGoKd=!M z4x?lT7(_n_;2Z8qw2@X&&9JR3&A^UySKX0@D-Sd671d$Vu;svMru1Sl->e3O9wuhf z*^s&3qvh38OlRmC{p_nf$Ghrt{w&RUwBF-m>}+pOuIdp$z$Kr7M#^io^0?mK`^3er zo+VCWRk%QRjE@!Vd9+6SA3NQSHN8lNFKxHYP4>S{7ld~GL@V3?FzP}Tk{E7m&;)bq zfklDzm$;rX7K&5-9x?}Fddp@~ny%L8cN3C{GaA!RQ*kllDLTe*gdnjU;%gwFZDNO(}4>?zOhhd z$8)heFD8wV!&+ODBlvV7s$=$plT)1A@Q9nG5Bt5Q#c?$fAUq$XDkSu)8N9kg7r7KM z#Ksi$D2s2=xb;+bwcTQ@v61w}Y9lSD@$GUj9tve{{N#i_`ds|z-Lb0RPK4u_u+$+l zk40jj9sRuG@CSxD;nlokY69QGq{-s+Tk@L(a+diqA2En^eP(Jn?X36nL+@X~2yzJ9 zm10!z{$;CXY1Vk*z&7mOv(MR9QP61B__QGv8m9Kv@_TBeD6HV@2#r{HHIgN~T9#=A zftza6Iz|$T)a}#sq%lwdR0$Zbbs1%`gr{tUu=H@8>__A!e__8*+r^V^^)I6WmbfSc zNY>-k*a84ShRUEowLpB5G=cXj0J##fQ+;^5d_wdlp`nSo&Mzj1=A3K=QzGnu7jDa2 z`UNQ;_+sA==XJk(4O5{vBH8BpJE)+MkXlsM&Ag^>)B^BU%(V>z(kJ~_DftoTO|PlD z%e6@ZMO7oPhqiIBq+9rilI7jYEw&%7y64cU;Aso+&TJ*;1R}3M>sVywJFrVhSz8x} z-j8pcV>gCiUncCIB1M-B`8H;Jog>qu1hb{{TRS(m-}B9V*1-qa4UVscfIK?W;=lif zaP&2gsst`Mv)Q=N9hWUFHp?++ zkfIfk`!m}cry}VHD#DqZKZFX1ad66q_v-KNnS^X`TM58s zXuEfTQ-(l*$Wy!$(6PIn_KlAr&kDs9x4Y~@mVGx|*uMTbYGzl4;IjS_mm1$&5t1R} zkCCWR^7$Ub<0)V1$6_3Y{STu1<}49}gB=iVotOcZst4eqaIqyzEa)JD;*zE%UrO42 zZDk4yorFWGok2?o1dvL-W_vEiU6KS~P9+QoCPR}~n;Inxd_cG*f65f^U+OOt!FCYr zS9XpJ7@0Tm$sN(A{X3{7<~)T#3qsaubaSvAoA1Z>^=h|fmJf1AN0pZ7Q_zt&f3}*b ztlX7(1HZ-vnKVC(&F<8?CFlin6j1X)0fC3&+K~CgODbT*ePhtkhTf;G4iEV%2ciw~ z+oD4ge%y|!LkStJ#t`Y(#eg*3c>NEpV@*u_mY?j)(a7U0O>OI<{42R(7F-rE^5*$R z8;XmMq&48M=y*~mdMt0P`xcUoJ=uFTk&*pCZZmVYcW_2@+-%WL_SJ(1&5!=C6W15{ z37gM|8MbUQDG~>^z5`jAxAsfrl&}r6!HgF|`a(%8!E^R7BFCh2Yk?SVk;Fynn5}Jc zr2~Z;yft5xEP*9HXgvsq>PwbdPd%H#DJ{%AnSEBw%@xn8E8LKy9jF zSTtJsaCZXhM%kJjx?j_5Sa&x)WxKc5gB3>B!_ED)RtTeDT2he^hT%pK zUTeoHEj*d3Ut}2PoONC2FLjJ9=GwLhngbJWio)wO;AbKosD^zQ zPs;kR%###9<9ga7y(onO@N>A`G)1Q2r6$sR#C#W!Qj+#;H zP3o$?jWurBe%|c3v!l?S9Qel`6Qa8}F>anB)iIQKuR3VO;)=Niu>7SEtrR4b^{Xmo zHeGhjtgF2LV?<@bMu3B-Pd!ZNcwbF0?{>_Hr(O(i>P4)VdeXH}l3i|anqfVX>Qz%0 z?)0v%zcLy#kSxqTW4OZFmYEXPC-B?L?eZ6DziBX~%`~{g`0a~nFO8Klg^=Or9rcX6 zcOwp0HB=Ro8;)eUK;jv16g29Q+_-ffaTSpQX@nYLuPBxMpTt}cSb*$SD{?Xx`B|Xt zIa5QBE^SJ^fbAcmrgJ&5TAiEA3Mi=nm)LqgVDmBQ)F||jC0t>aRct=CnT-?XBk`kh zJDHm&+)l1)|GmKqxNA)gcv%G$N`2j;HNHmv19V{shzU5(x~5~F{M3duS$6*Dp==0( z;K%vMW#k+VBB=NV9qI;UY$wcB{Laza_Li-$nhfW9?v;%w~f zmwc)FOx#^%VEm166M~Hlp~F>{gu6bQc|%xXG+i|}Vu5Tt)idW=YAvz(`va@XSJ7$B zOuQW>uL!(_vIQBm7!aS{t*jlSxsl^u`x2ABmsbPZNKXv6b0j`rBwfN5C*GdQIcjE3 z5OI@6*?6dYL}L@;uuvJP3^5wCp`604e9k}2=qRxs=!sjtTng+rt7+XX5D-K6oz{k2 z=Ru&5Xb|0SQ4N3<*hbqC5~MFIvL_VharCE#lYeZctJcMlmd7XqaWE(N;WS6-77Qip_}az(uqXgNAaUTjy<-w2QA<$e+t2PNnQ?l z@rkOX_4*}msQQn_&o{>1-9>Xb#O$>}22c6;PwL*Ao((umFAfW}1ZK`@)VGf2ug1DZ zS^~qH>+(F72D0r&b5{my`?&ctl;i0QyAaYoRq*;Y{)r|ALQ-Zah6LnHP%v*MPxU7Y zp1ddlS;lBrtSarTcbL;cT9E^6a^u_?`_tN#A4@&t_WZ;Vb;QcpKm$bn;X@_k zO)2_#PolqHYu2KV$Vf7VEg(=tcc8I3a;QaFh_Nn^WhvuHo$XX{NJveOs-)*{Erkc$ zPcx4_jM08uK_7Aa2_&V4jK6eDHG-f!hWT_Bd-JZJlKtYhaosA6?6+{i z%A5K6yn6$u7vT5?OnRayO2-k3tR?~|rzmFUy uZ|A*qn~t||t&;y2xcOfwHW+lo;CcTwh3D7TnTiu|4(RI`X}{8RjQI}@zp=Xj literal 1336 zcmZuwdrVVT7{9j#c?Ab5K446Spb(8X#Z4H~D~bZs+5m0o1O#!b5rbtgL7cM^GjYWD zh*NMpiiHhjq8qxwT%-dEqAlf7p#@qCr0u0BC30`?qqTRpi-!H-Ip6pFzUTSAlaq6v z&D!nl>F)^ufOkUt&LkQ|PIhO~6475KXaMt*cE^I6o^_{b!$TO)&j$dn#ZCr+8En56<3~7Z0T(wK#<-tp`P;`(bjofw+wC{aufyby1s#+e!-o&2U{mlI zZ>!O2rMuGvwo}7`6dZ=Nylu4kQUB{<0oRCGZ=u#<0jC+aY6LvoWYqGuYB({|4PtZS zO><-IbfW~W{&76OXN(_f!0{K&w{>>AF5G|iNe_L<^N?leh#DDDPoB!9Z%UJ~uF@#J zX1IEeP8&^&e0BmczC z0`DYnElDKSKCPkOwXz_Il?;ffw`*Q|>!GOs`J8Gd`^#2@qJ$LXE^-3nP3EQf3X71c zaif&Y7i%n;G|dN`8eK?<=ri*yxdJd2p1iw^|6 zLqHV_fVZ)wVN>FF%NCZlJldFBryg`?`&HOC*QQ?p{2bG9dM3ni^c-01sPz@IUYhPk z5$UUfCW>l)ihGWLtjX(THv>{$m2%`)4U}D*|QCf&b3f=N#~lJ zsN9nws*wD`b6m*QAawLy^~-TBNW3Vc6g6CFQyEs08l4IK7P0yf$fzm7*UMN*sJt-1J=9j8{WYuj)rwE{2auiFYebTW x0;-+0a_xopivxuQ@=iIxa1Ro_L+F=-3qc@Uer6_ysi8jtkPye(*%X^u@-NKF|GWSI diff --git a/content/content.js b/content/content.js index 630a3a7..14a5a98 100644 --- a/content/content.js +++ b/content/content.js @@ -12,7 +12,7 @@ function scriptInjector() { const scriptElem = document.createElement("script"); scriptElem.src = chrome.runtime.getURL("/content/utils.js"); scriptElem.type = "module"; - document.head.appendChild(scriptElem); + document.head.append(scriptElem); scriptElem.addEventListener("load", initUtilities); } @@ -101,14 +101,15 @@ function enableDragElement(elmnt) { } } +createSidebar() const enemiesDiv = createEnemyDiv() const alliesDiv = createAlliesDiv() enableDragElement(enemiesDiv); enableDragElement(alliesDiv); -document.body.appendChild(enemiesDiv); -document.body.appendChild(alliesDiv); +document.body.append(enemiesDiv); +document.body.append(alliesDiv); let Types (function (Types) { @@ -179,7 +180,7 @@ function createTypeEffectivenessWrapper(typeEffectivenesses) { `).join('')} ${createTooltipDiv(tooltipMap[effectiveness] || "")}
- ` + ` }).join('')} ` return typesHTML @@ -316,7 +317,7 @@ function generateIVsHTML(pokemon, dexIvs){ for (let i in pokemon.ivs) { let curIV = pokemon.ivs[i]; fullHTML += `
${Stat[i]}: 
${curIV}${ivComparison(curIV, dexIvs[i])}
  
`; - // ivsRow.appendChild(statDiv); + // ivsRow.append(statDiv); } return fullHTML; } @@ -412,6 +413,7 @@ async function getPokemonIcon(pokemon, divId) { if (cachedImage) { console.log('Using cached image'); + const blobUrl = cachedImage; imageCache[cacheKey] = blobUrl; // Save to memory cache if loaded from local storage loadImageFromBlobUrl(image1, blobUrl).then(() => { @@ -500,11 +502,6 @@ async function getPokemonIcon(pokemon, divId) { console.log(pokemon); } - - - - - async function createPokemonCardDiv_minified(cardId, pokemon) { let savedData = Utils.LocalStorage.getPlayerData(); let dexData = savedData["dexData"]; @@ -605,35 +602,112 @@ async function chooseCardType(divId, pokemon, minified){ } } -async function createCardsDiv(divId, pokemon) { +async function createCardsDiv(divId, pokemonData, pokemonIndex) { + const pokemon = pokemonData[pokemonIndex] let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); let newDiv = createWrapperDiv(divId); - return await chooseCardType(divId, pokemon, extensionSettings.showMinified).then(async (cardObj) =>{ - const buttonsObj = createArrowButtonsDiv(divId, "↑", "↓", extensionSettings.showMinified); - const cardsHTML = ` - ${buttonsObj.html} - ${cardObj.html} - `; - newDiv.insertAdjacentHTML("afterbegin", cardsHTML) - document.body.appendChild(newDiv); - getPokemonIcon(pokemon, divId); - if(cardObj.slider) { + + return await chooseCardType(divId, pokemon, extensionSettings.showMinified).then(async (cardObj) =>{ + const buttonsObj = createArrowButtonsDiv(divId, "↑", "↓", extensionSettings.showMinified); + const cardsHTML = ` + ${buttonsObj.html} + ${cardObj.html} + `; + newDiv.insertAdjacentHTML("afterbegin", cardsHTML) + document.body.append(newDiv); + getPokemonIcon(pokemon, divId); + + if(cardObj.slider) { document.getElementById(cardObj.slider).addEventListener('input', changeOpacity) - } - document.getElementById(buttonsObj.idUp).addEventListener('click', (event)=>{ + } + document.getElementById(buttonsObj.idUp).addEventListener('click', (event)=>{ changePage(event); - }) - document.getElementById(buttonsObj.idDown).addEventListener('click', (event)=>{ + }) + document.getElementById(buttonsObj.idDown).addEventListener('click', (event)=>{ changePage(event); - }) - return newDiv + }) + return newDiv }) +} +function createSidebar() { + const sidebarHtml = ` +
+ + + +
+ ` + document.body.insertAdjacentHTML("afterbegin", sidebarHtml) +} + +/* + Updates party information for both sides (allies, enemies) in the sidebar. +*/ +async function updateSidebarCards(partyID, sessionData, pokemonData) { + const sidebarPartyElement = document.getElementById(`sidebar-${partyID}-box`) + const extensionSettings = await Utils.LocalStorage.getExtensionSettings() + let savedData = Utils.LocalStorage.getPlayerData() + let dexData = savedData["dexData"] + + sidebarPartyElement.replaceChildren(); + + let partyHeader = ''; + if (extensionSettings.showParty && (partyID == 'enemies')) { + partyHeader = `` + } + else if (extensionSettings.showEnemies && (partyID == 'allies')) { + partyHeader = `` + } - + let partyHtml = ` + ${partyHeader} + + ${pokemonData.pokemon.map((pokemon, counter) => ` + + `).join('')} + ` + sidebarPartyElement.insertAdjacentHTML("afterbegin", partyHtml) + + pokemonData.pokemon.forEach(function (value, i) { + getPokemonIcon(value, `sidebar_${partyID}_${i}`) + }) } - function deleteAllChildren(element) { while (element.firstChild) { element.removeChild(element.firstChild); @@ -654,7 +728,6 @@ function deleteWrapperDivs() { } } - async function scaleElements() { const data = await browserApi.storage.sync.get('scaleFactor'); const scaleFactorMulti = data.scaleFactor || 1; @@ -667,19 +740,76 @@ async function scaleElements() { let scaleFactor = scaleFactor_width < scaleFactor_height ? scaleFactor_width : scaleFactor_height; const enemiesDiv = document.getElementById('enemies'); const alliesDiv = document.getElementById('allies'); + const sidebarEnemiesDiv = document.getElementById('sidebar-enemy-box'); enemiesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; alliesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; + sidebarEnemiesDiv.style.fontSize = `${12 * scaleFactor * scaleFactorMulti}px`; +} + +async function toggleSidebar() { + const data = await browserApi.storage.sync.get('showSidebar') + const sidebarToggleState = data.showSidebar + let sidebarElement = document.getElementById('roguedex-sidebar') + let gameAppElement = document.getElementById('app') + let runningStatusElement = document.getElementsByClassName('running-status')[0] + let enemyCardDiv = document.getElementById('enemies') + let allyCardDiv = document.getElementById('allies') + + if (sidebarToggleState === true) { + sidebarElement.classList.remove('hidden') + sidebarElement.classList.add('active') + gameAppElement.classList.add('sidebar-active') + runningStatusElement.classList.add('sidebar-active') + + allyCardDiv.classList.add('hidden') + enemyCardDiv.classList.add('hidden') + console.log("SIDEBAR toggled ON, #enemies and #allies DOM elements (pokemon cards) have been hidden via css classes.") + } else if (sidebarToggleState === false) { + sidebarElement.classList.remove('active') + sidebarElement.classList.add('hidden') + gameAppElement.classList.remove('sidebar-active') + runningStatusElement.classList.remove('sidebar-active') + + allyCardDiv.classList.remove('hidden') + enemyCardDiv.classList.remove('hidden') + console.log("SIDEBAR toggled OFF, #enemies and #allies DOM elements (pokemon cards) have been shown again via css classes.") + } +} + +async function changeSidebarPosition() { + const data = await browserApi.storage.sync.get('sidebarPosition') + const sidebarPosition = data.sidebarPosition + let sidebarParentElement = document.body + + sidebarParentElement.classList.remove('sidebar-Left', 'sidebar-Right', 'sidebar-Top', 'sidebar-Bottom') + sidebarParentElement.classList.add(`sidebar-${sidebarPosition}`) +} + +async function toggleSidebarPartyDisplay(partyID, state) { + let sidebarPartyElement = document.getElementById(`sidebar-${partyID}-box`) + if (state) { + sidebarPartyElement.classList.add('visible') + sidebarPartyElement.classList.remove('hidden') + } + else { + sidebarPartyElement.classList.remove('visible') + sidebarPartyElement.classList.add('hidden') + } } async function initCreation(sessionData) { deleteWrapperDivs(); - let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); + let extensionSettings = await Utils.LocalStorage.getExtensionSettings() if (extensionSettings.showEnemies) { await dataMapping("enemyParty", "enemies", sessionData); } if (extensionSettings.showParty) { await dataMapping("party", "allies", sessionData); } + if (extensionSettings.showSidebar) { + await toggleSidebar(sessionData); + await changeSidebarPosition(sessionData); + } } async function dataMapping(pokemonLocation, divId, sessionData) { @@ -687,9 +817,10 @@ async function dataMapping(pokemonLocation, divId, sessionData) { weather = pokemonData.hasOwnProperty('weather') ? pokemonData.weather : null; partySize[divId] = pokemonData.pokemon.length; let pIndex = determinePage(divId, pokemonData.pokemon); - await createCardsDiv(divId, pokemonData.pokemon[pIndex]).then(() => { + await createCardsDiv(divId, pokemonData.pokemon, pIndex).then(() => { scaleElements(); - }); + }); + await updateSidebarCards(divId, sessionData, pokemonData); }); } @@ -704,7 +835,7 @@ function determinePage(divId, pokemon) { function extensionSettingsListener() { browserApi.storage.onChanged.addListener(async function (changes, namespace) { - for (let [key, {oldValue, newValue}] of Object.entries(changes)) { + for (let [key, values = {oldValue, newValue}] of Object.entries(changes)) { if (key === 'showMinified') { let sessionData = Utils.LocalStorage.getSessionData(); await initCreation(sessionData); @@ -715,10 +846,20 @@ function extensionSettingsListener() { if (key === 'showEnemies') { let sessionData = Utils.LocalStorage.getSessionData(); await initCreation(sessionData); + await toggleSidebarPartyDisplay('enemies', values.newValue); } if (key === 'showParty') { let sessionData = Utils.LocalStorage.getSessionData(); await initCreation(sessionData); + await toggleSidebarPartyDisplay('allies', values.newValue); + } + if (key === 'showSidebar') { + let sessionData = Utils.LocalStorage.getSessionData(); + await toggleSidebar(sessionData); + } + if (key === 'sidebarPosition') { + let sessionData = Utils.LocalStorage.getSessionData(); + await changeSidebarPosition(sessionData); } } }); @@ -763,19 +904,24 @@ function listenForDataUiModeChange() { if (mutation.type === 'attributes' && mutation.attributeName === 'data-ui-mode') { const newValue = touchControlsElement.getAttribute('data-ui-mode'); console.log('New value:', newValue); - // Existing logic for handling data-ui-mode changes - if (newValue === "MESSAGE" || newValue === "COMMAND" || newValue === "CONFIRM") { - Utils.LocalStorage.setSessionData(); - let sessionData = Utils.LocalStorage.getSessionData(); - await initCreation(sessionData); - } - if (newValue === "SAVE_SLOT") { - Utils.LocalStorage.clearAllSessionData(); - } - if (newValue === "SAVE_SLOT" || newValue === "TITLE" || newValue === "MODIFIER_SELECT" || newValue === "STARTER_SELECT") { - deleteWrapperDivs() - } + // Existing logic for handling data-ui-mode changes + if (newValue === "MESSAGE" || newValue === "COMMAND" || newValue === "CONFIRM") { + try { + Utils.LocalStorage.setSessionData(); + let sessionData = Utils.LocalStorage.getSessionData(); + await initCreation(sessionData); + } + catch (err) { + console.error(err) + } + } + if (newValue === "SAVE_SLOT") { + Utils.LocalStorage.clearAllSessionData(); + } + if (newValue === "SAVE_SLOT" || newValue === "TITLE" || newValue === "MODIFIER_SELECT" || newValue === "STARTER_SELECT") { + deleteWrapperDivs() + } } }); }); diff --git a/content/util_classes/localStorage.util.js b/content/util_classes/localStorage.util.js index 93e06e5..f1771d6 100644 --- a/content/util_classes/localStorage.util.js +++ b/content/util_classes/localStorage.util.js @@ -64,7 +64,7 @@ class LocalStorageClass { async getExtensionSettings() { return new Promise((resolve) => { - browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty'], (data) => { + browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty', 'showSidebar', 'sidebarPosition'], (data) => { if (data.showMinified === undefined) { browserApi.storage.sync.set({ 'showMinified': false }); data.showMinified = false; @@ -81,6 +81,14 @@ class LocalStorageClass { browserApi.storage.sync.set({ 'showParty': true }); data.showParty = true; } + if (data.showSidebar === undefined) { + browserApi.storage.sync.set({ 'sideBar': false }); + data.showSidebar = false; + } + if (data.sidebarPosition === undefined) { + browserApi.storage.sync.set({ 'sidebarPosition': 'Left' }); + data.showSidebar = 'Left'; + } resolve(data); }); }); diff --git a/manifest.json b/manifest.json index f57ec1e..9694ca2 100644 --- a/manifest.json +++ b/manifest.json @@ -5,9 +5,7 @@ "permissions": [ "activeTab", "webRequest", - "storage", - "https://if.daena.me/*", - "https://cdn.daena.me/*" + "storage" ], "host_permissions": [ "https://pokerogue.net/*", @@ -60,6 +58,11 @@ ] } ], + "icons": { + "16": "RogueDex.png", + "48": "RogueDex.png", + "128": "RogueDex.png" + }, "web_accessible_resources": [ { "resources": [ diff --git a/options/generateSettingsUI.js b/options/generateSettingsUI.js index 19c3b05..5c04ee7 100644 --- a/options/generateSettingsUI.js +++ b/options/generateSettingsUI.js @@ -31,6 +31,8 @@ const generateSettingsUI = () => { label.classList.add('bool-label'); } else if (setting.type === 'Float' || setting.type === 'Int') { span.setAttribute('data-value', option); + } else if (setting.type === 'String') { + span.setAttribute('data-value', option); } settingOptions.appendChild(span); diff --git a/options/optionsManager.js b/options/optionsManager.js index eed01c3..d2c93a0 100644 --- a/options/optionsManager.js +++ b/options/optionsManager.js @@ -35,6 +35,9 @@ class OptionsManager { if (data[setting] === (setting === 'menuType' || setting === 'scaleFactor' ? parseFloat(value) : value === 'true')) { option.classList.add('selected'); } + else if (setting === 'sidebarPosition' && (data[setting] === value)) { + option.classList.add('selected'); + } }); if (callback) { @@ -61,13 +64,17 @@ class OptionsManager { const showParty = document.querySelector('.option[data-setting="showParty"].selected').getAttribute('data-value') === 'true'; const scaleFactor = document.getElementById('scaleSlider').value; const menuType = parseInt(document.querySelector('.option[data-setting="menuType"].selected').getAttribute('data-value'), 10); + const showSidebar = document.querySelector('.option[data-setting="showSidebar"].selected').getAttribute('data-value') === 'true'; + const sidebarPosition = document.querySelector('.option[data-setting="sidebarPosition"].selected').getAttribute('data-value') === 'true'; this.browserApi.storage.sync.set({ 'showMinified': showMin, 'scaleFactor': scaleFactor, 'showEnemies': showEnemy, 'showParty': showParty, - 'menuType': menuType + 'menuType': menuType, + 'showSidebar': showSidebar, + 'sidebarPosition': sidebarPosition }, () => { if (this.browserApi.runtime.lastError) { console.error('Error saving options:', this.browserApi.runtime.lastError); diff --git a/options/settingsTemplate.js b/options/settingsTemplate.js index 93d9248..4e31b78 100644 --- a/options/settingsTemplate.js +++ b/options/settingsTemplate.js @@ -29,6 +29,18 @@ const settingsTemplate = { options: ["1", "2", "3", "4", "5"], localStorage: "menuType", type: "Int" + }, + 5: { + text: "Show Sidebar", + options: ["No", "Yes"], + localStorage: "showSidebar", + type: "Bool" + }, + 6: { + text: "Sidebar Position", + options: ["Left", "Right" /*,"Top", "Bottom"*/], + localStorage: "sidebarPosition", + type: "String" } }; diff --git a/styles.css b/styles.css index eaa5640..4718be9 100644 --- a/styles.css +++ b/styles.css @@ -3,160 +3,320 @@ /* --icon-size: min(10vh, 6vw);*/ /*}*/ +:root { + --icon-size: min(1.5em); + --type-effectiveness-border-width: 2px; + --type-effectiveness-item-margin: 0.1em; + /* needs media query for bigger screens */ + --sidebar-img-max-height: max(90px); +} + +/* pokerogue overwrites */ +body { + display: flex; +} +#app { + display: block; +} +/* apply to game app when sidebar is visible */ +#app.sidebar-active { + max-width: 70%; + float: right; +} + +/* temporary fix for no UI method to open sidebar and hiding other overlays implemented */ +#enemies.hidden, +#allies.hidden { + display: none; +} + +/* roguedex sidebar */ +.roguedex-sidebar { + float: left; + height: auto; + width: 30%; + background-color: #0000005e; + overflow-y: auto; + overflow-x: hidden; + display: none; +} +.roguedex-sidebar.active { + display: block; +} +.roguedex-sidebar.hidden { + display: none; +} +.running-status { + max-width: 30%; + display: flex; +} +body.sidebar-Left { + flex-direction: row; +} +body.sidebar-Right { + flex-direction: row-reverse; +} +body.sidebar-Top { + flex-direction: column; +} +body.sidebar-Bottom { + flex-direction: column-reverse; +} +.running-status.sidebar-active { + display: none; +} +.roguedex-sidebar .sidebar-header { + color: white; + font-size: 2em; + padding: 0.1em 0 0.3em 0; + width: 100%; + text-align: center; + font-family: emerald; +} +.roguedex-sidebar .sidebar-enemies-box, .roguedex-sidebar .sidebar-allies-box { + display: block; + width: 100%; + margin-right: 0.1em; +} +.roguedex-sidebar .sidebar-enemies-box.hidden, .roguedex-sidebar .sidebar-allies-box.hidden { + display: none; +} +.roguedex-sidebar .sidebar-enemies-box.visible, .roguedex-sidebar .sidebar-allies-box.visible { + display: block; +} +.roguedex-sidebar .sidebar-party-header { + text-shadow: none; + color: white; + padding: 0 0.5em; + text-align: center; + font-size: 1.5em; + background-color: #00000040; +} +.roguedex-sidebar .pokemon-card { + display: flex; + flex-basis: auto; + flex-direction: row; + padding: 0.2em 0.2em 0.2em 0; + margin-bottom: 2px; + flex-wrap: wrap; +} +.roguedex-sidebar .pokemon-card-text-block { + padding-left: 0.2em; +} +.roguedex-sidebar .pokemon-card-text-block .text-base { + text-shadow: none; + color: white; + padding: 0; +} +.roguedex-sidebar .pokemon-card-text-block .tooltiptext { + text-shadow: none; + color: black; +} +.roguedex-sidebar .pokemon-card .text-base { + padding: 0 0 0 0.5em; +} +.pokemon-card-text-block .stat-cont { + display: flex; + flex-wrap: wrap; + padding: 0; +} +.pokemon-card-text-block .stat-p { + display: flex; + flex: 0 0 33.3333%; + padding: 0; +} +.roguedex-sidebar .pokemon-card-graphics-block { + max-height: var(--sidebar-img-max-height); + display: flex; +} +.roguedex-sidebar .pokemon-weaknesses, +.roguedex-sidebar .pokemon-resistances, +.roguedex-sidebar .pokemon-immunities { + border-width: var(--type-effectiveness-border-width); + min-width: fit-content; + display: flex; + min-height: calc(var(--icon-size) * 1); +} +.roguedex-sidebar .type-icon { + max-width: calc( + ( + var(--sidebar-img-max-height) - + (var(--type-effectiveness-border-width) * 2) - + (var(--type-effectiveness-item-margin) * 6) + ) / 3 + ); + max-height: calc( + ( + var(--sidebar-img-max-height) - + (var(--type-effectiveness-border-width) * 2) - + (var(--type-effectiveness-item-margin) * 6) + ) / 3 + ); +} + +/* */ + .allies-team { - margin: 0 auto; - padding: 0 auto; - position: absolute; - top: 0; - right: 0; - z-index: 1; - display: flex; + margin: 0 auto; + padding: 0 auto; + position: absolute; + top: 0; + right: 0; + z-index: 1; + display: flex; } .enemy-team { - margin: 0 auto; - padding: 0 auto; - position: absolute; - top: 0; - z-index: 1; - display: flex; + margin: 0 auto; + padding: 0 auto; + position: absolute; + top: 0; + z-index: 1; + display: flex; } -.stat-cont{ - +.stat-cont { } .pokemon-cards { - display: flex; - flex-wrap: nowrap; - overflow: hidden; + display: flex; + flex-wrap: nowrap; + overflow: hidden; } .pokemon-card { - background-color: #333333b8; - border: 2px solid #555; - border-radius: 8px; - flex: 0 0 auto; - display:flex; - flex-direction: column; + background-color: #333333b8; + border: 2px solid #555; + border-radius: 8px; + flex: 0 0 auto; + display: flex; + flex-direction: column; } .pokemon-icon img { - width: 5em; - height: 5em; + width: 5em; + height: 5em; } .pokemon-info { - margin-top: 10px; + margin-top: 10px; } .pokemon-types { - display: flex; - justify-content: center; - margin-bottom: 10px; + display: flex; + justify-content: center; + margin-bottom: 10px; } .type-icon { - width: 1.5em; - height: 1.5em; - background-size: cover; - background-repeat: no-repeat; - background-position: left; - background-position-x: -0.07em; - border-radius: 50%; - margin: 0 0.3em; + width: var(--icon-size); + height: var(--icon-size); + background-size: cover; + background-repeat: no-repeat; + background-position: left; + background-position-x: -0.07em; + border-radius: 50%; + margin: 0.1em 0.1em; } .pokemon-weaknesses, .pokemon-resistances, .pokemon-immunities { - min-width: 2.5em; - display: flex; - min-height: 5em; + min-width: var(--icon-size); + display: flex; + min-height: 5em; } .pokemon-weaknesses { - background-color: #6a1f1f; - border: 2px solid red; - border-radius: 10px; + background-color: #6a1f1f; + border: 2px solid red; + border-radius: 10px; } .pokemon-resistances { - background-color: #216a1f; - border: 2px solid green; - border-radius: 10px; + background-color: #216a1f; + border: 2px solid green; + border-radius: 10px; } .pokemon-immunities { - background-color: #484848; - border: 2px solid white; - border-radius: 10px; + background-color: #484848; + border: 2px solid white; + border-radius: 10px; } .pokemon-weaknesses .type-icon, .pokemon-resistances .type-icon, .pokemon-immunities .type-icon { - opacity: 1; + opacity: 1; } .text-base { - display: flex; - font-family: 'emerald'; - font-size: 1em; - text-shadow: 0.1em 0 #fff, -0.1em 0 #fff, 0 0.1em #fff, 0 -0.1em #fff, 0.05em 0.05em #fff, -0.05em -0.05em #fff, 0.05em -0.05em #fff, -0.05em 0.05em #fff; - color: black; + display: flex; + font-family: 'emerald'; + font-size: 1em; + text-shadow: + 0.1em 0 #fff, + -0.1em 0 #fff, + 0 0.1em #fff, + 0 -0.1em #fff, + 0.05em 0.05em #fff, + -0.05em -0.05em #fff, + 0.05em -0.05em #fff, + -0.05em 0.05em #fff; + color: black; } .arrow-button-wrapper { - display: grid; + display: grid; } /*.arrow-button {*/ /* font-size: 2.5em;*/ /*}*/ -.centered-flex{ - display: flex; +.centered-flex { + display: flex; justify-content: center; } .tooltip .tooltiptext { - visibility: hidden; - text-align: center; - border-radius: 6px; - padding: 0.25em 0; - font-size: 1em; - position: absolute; - z-index: 1; - background-color: white; + visibility: hidden; + text-align: center; + border-radius: 6px; + padding: 0.25em 0; + font-size: 1em; + position: absolute; + z-index: 1; + background-color: white; } .tooltip:hover .tooltiptext { - visibility: visible; + visibility: visible; } -.image-overlay{ - position: absolute; - left: 20px; - top: -30px; - width: 96px; - height: 96px; +.image-overlay { + position: absolute; + left: 20px; + top: -30px; + width: 96px; + height: 96px; } /* Slider settings */ -@media screen and (-webkit-min-device-pixel-ratio:0) { +@media screen and (-webkit-min-device-pixel-ratio: 0) { input[type='range'] { - overflow: hidden; - width: 4em; - -webkit-appearance: none; + overflow: hidden; + width: 4em; + -webkit-appearance: none; } - + /*input[type='range']::-webkit-slider-runnable-track {*/ /* height: 0.1em;*/ /* -webkit-appearance: none;*/ /* color: #13bba4;*/ /* margin-top: -1px;*/ /*}*/ - + /*input[type='range']::-webkit-slider-thumb {*/ /* width: .1em;*/ /* -webkit-appearance: none;*/ @@ -164,62 +324,69 @@ /* cursor: ew-resize;*/ /* box-shadow: -.8em 0 0 .8em #b3462c;*/ /*}*/ - } /** FF*/ -input[type="range"]::-moz-range-progress { - background-color: #b3462c; +input[type='range']::-moz-range-progress { + background-color: #b3462c; } -input[type="range"]::-moz-range-track { - background-color: #fff; +input[type='range']::-moz-range-track { + background-color: #fff; } -input[type="range"] { - background-color:transparent +input[type='range'] { + background-color: transparent; } .slider-wrapper { - display: flex; + display: flex; } .running-status { - position: absolute; - width: 100%; - justify-content: center; - text-align: center; - color: blue; - background-color: #ffffff50; + position: absolute; + width: 100%; + justify-content: center; + text-align: center; + color: blue; + background-color: #ffffff50; } .hidden-ability { - color: #f700ff; + color: #f700ff; } .running-status { - position: absolute; - width: 100%; - justify-content: center; - text-align: center; - color: blue; - background-color: #ffffff50; + position: absolute; + width: 100%; + justify-content: center; + text-align: center; + color: blue; + background-color: #ffffff50; } .stat-p { - display: flex; - padding-right: 0.3em; - padding-top: 0.3em; + display: flex; + padding-right: 0.3em; + padding-top: 0.3em; } .stat-c { - position: relative; - text-shadow: 0.1em 0 rgba(255, 255, 255, 0), -0.1em 0 rgba(255, 255, 255, 0), 0 0.1em rgba(255, 255, 255, 0), 0 -0.1em rgba(255, 255, 255, 0), 0.05em 0.05em rgba(255, 255, 255, 0), -0.05em -0.05em rgba(255, 255, 255, 0), 0.05em -0.05em rgba(255, 255, 255, 0), -0.05em 0.05em rgba(255, 255, 255, 0); + position: relative; + text-shadow: + 0.1em 0 rgba(255, 255, 255, 0), + -0.1em 0 rgba(255, 255, 255, 0), + 0 0.1em rgba(255, 255, 255, 0), + 0 -0.1em rgba(255, 255, 255, 0), + 0.05em 0.05em rgba(255, 255, 255, 0), + -0.05em -0.05em rgba(255, 255, 255, 0), + 0.05em -0.05em rgba(255, 255, 255, 0), + -0.05em 0.05em rgba(255, 255, 255, 0); } .stat-icon { - position: absolute; - top: -0.3em; - right: -0.5em; + position: absolute; + top: -0.3em; + right: -0.5em; } -.op-slider{ - width: 100% !important; -} \ No newline at end of file +.op-slider { + width: 100% !important; +} From c9398e08e6f4ac6795d292b0dd0c952f111cd1f0 Mon Sep 17 00:00:00 2001 From: Eruyome Date: Fri, 24 May 2024 11:30:59 +0200 Subject: [PATCH 13/78] Implemented and fixed sidebar scaling (via options menu) --- content/content.js | 22 +++++++++++++++++++--- content/util_classes/localStorage.util.js | 6 +++++- options/optionsManager.js | 10 ++++++---- options/settingsTemplate.js | 7 +++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/content/content.js b/content/content.js index 14a5a98..d9fffcf 100644 --- a/content/content.js +++ b/content/content.js @@ -740,10 +740,23 @@ async function scaleElements() { let scaleFactor = scaleFactor_width < scaleFactor_height ? scaleFactor_width : scaleFactor_height; const enemiesDiv = document.getElementById('enemies'); const alliesDiv = document.getElementById('allies'); - const sidebarEnemiesDiv = document.getElementById('sidebar-enemy-box'); enemiesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; - alliesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; - sidebarEnemiesDiv.style.fontSize = `${12 * scaleFactor * scaleFactorMulti}px`; + alliesDiv.style.fontSize = `${16 * scaleFactor * scaleFactorMulti}px`; +} + +/* should probably refactor this and combine it with the scaleElements() function */ +async function scaleSidebarElements() { + const data = await browserApi.storage.sync.get('sidebarScaleFactor'); + const scaleFactorMulti = data.sidebarScaleFactor || 1; + const baseWidth = 1920; // Assume a base width of 1920 pixels + const baseHeight = 1080; // Assume a base height of 1080 pixels + const currentWidth = window.innerWidth; + const currentHeight = window.innerHeight; + const scaleFactor_width = currentWidth / baseWidth; + const scaleFactor_height = currentHeight / baseHeight; + let scaleFactor = scaleFactor_width < scaleFactor_height ? scaleFactor_width : scaleFactor_height; + const sidebarDiv = document.getElementById('roguedex-sidebar'); + sidebarDiv.style.fontSize = `${12 * scaleFactor * scaleFactorMulti}px`; } async function toggleSidebar() { @@ -861,6 +874,9 @@ function extensionSettingsListener() { let sessionData = Utils.LocalStorage.getSessionData(); await changeSidebarPosition(sessionData); } + if (key === 'sidebarScaleFactor') { + await scaleSidebarElements(); + } } }); } diff --git a/content/util_classes/localStorage.util.js b/content/util_classes/localStorage.util.js index f1771d6..35d3589 100644 --- a/content/util_classes/localStorage.util.js +++ b/content/util_classes/localStorage.util.js @@ -64,7 +64,7 @@ class LocalStorageClass { async getExtensionSettings() { return new Promise((resolve) => { - browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty', 'showSidebar', 'sidebarPosition'], (data) => { + browserApi.storage.sync.get(['showMinified', 'scaleFactor', 'showEnemies', 'showParty', 'showSidebar', 'sidebarPosition', 'sidebarScaleFactor'], (data) => { if (data.showMinified === undefined) { browserApi.storage.sync.set({ 'showMinified': false }); data.showMinified = false; @@ -89,6 +89,10 @@ class LocalStorageClass { browserApi.storage.sync.set({ 'sidebarPosition': 'Left' }); data.showSidebar = 'Left'; } + if (data.sidebarScaleFactor === undefined) { + browserApi.storage.sync.set({ 'sidebarScaleFactor': 1 }); + data.sidebarScaleFactor = 1; + } resolve(data); }); }); diff --git a/options/optionsManager.js b/options/optionsManager.js index d2c93a0..fb6199f 100644 --- a/options/optionsManager.js +++ b/options/optionsManager.js @@ -7,7 +7,7 @@ class OptionsManager { saveOption(setting, value) { const settings = {}; - if (setting === 'menuType' || setting === 'scaleFactor') { + if (setting === 'menuType' || setting === 'scaleFactor' || setting === 'sidebarScaleFactor') { settings[setting] = parseFloat(value); } else if (value === 'true' || value === 'false') { settings[setting] = value === 'true'; @@ -32,7 +32,7 @@ class OptionsManager { document.querySelectorAll('.setting-options .option').forEach(option => { const setting = option.getAttribute('data-setting'); const value = option.getAttribute('data-value'); - if (data[setting] === (setting === 'menuType' || setting === 'scaleFactor' ? parseFloat(value) : value === 'true')) { + if (data[setting] === (setting === 'menuType' || setting === 'scaleFactor' || setting === 'sidebarScaleFactor' ? parseFloat(value) : value === 'true')) { option.classList.add('selected'); } else if (setting === 'sidebarPosition' && (data[setting] === value)) { @@ -50,7 +50,7 @@ class OptionsManager { updateScale(value) { const scaleFactor = parseFloat(value); document.getElementById('scaleValue').textContent = scaleFactor; - // Update any other necessary elements based on scale factor + // Update any other necessary elements based on scale factor } scaleElements() { @@ -66,6 +66,7 @@ class OptionsManager { const menuType = parseInt(document.querySelector('.option[data-setting="menuType"].selected').getAttribute('data-value'), 10); const showSidebar = document.querySelector('.option[data-setting="showSidebar"].selected').getAttribute('data-value') === 'true'; const sidebarPosition = document.querySelector('.option[data-setting="sidebarPosition"].selected').getAttribute('data-value') === 'true'; + const sidebarScaleFactor = parseFloat(document.querySelector('.option[data-setting="sidebarScaleFactor"].selected').getAttribute('data-value')); this.browserApi.storage.sync.set({ 'showMinified': showMin, @@ -74,7 +75,8 @@ class OptionsManager { 'showParty': showParty, 'menuType': menuType, 'showSidebar': showSidebar, - 'sidebarPosition': sidebarPosition + 'sidebarPosition': sidebarPosition, + 'sidebarScaleFactor': sidebarScaleFactor }, () => { if (this.browserApi.runtime.lastError) { console.error('Error saving options:', this.browserApi.runtime.lastError); diff --git a/options/settingsTemplate.js b/options/settingsTemplate.js index 4e31b78..5a52b04 100644 --- a/options/settingsTemplate.js +++ b/options/settingsTemplate.js @@ -41,6 +41,13 @@ const settingsTemplate = { options: ["Left", "Right" /*,"Top", "Bottom"*/], localStorage: "sidebarPosition", type: "String" + }, + 7: { + text: "Sidebar Scale", + options: ["0.5", "1.0", "1.5", "2.0","2.5","3.0"], + appendText: "x", + localStorage: "sidebarScaleFactor", + type: "Float" } }; From ab482259e9dddaa1b9b271d5c1581b8b461fb4d8 Mon Sep 17 00:00:00 2001 From: Eruyome Date: Fri, 24 May 2024 17:00:30 +0200 Subject: [PATCH 14/78] Added css animations for super-effective and super-resistand types in the sidebar. Quick and dirty implementation. But that information (x4 dmg, x0.25) was sorely missing. --- content/content.js | 20 ++- content/util_classes/pokemonMapper.util.js | 134 +++++++++++++++++++++ styles.css | 19 +++ 3 files changed, 170 insertions(+), 3 deletions(-) diff --git a/content/content.js b/content/content.js index d9fffcf..f157e01 100644 --- a/content/content.js +++ b/content/content.js @@ -153,7 +153,11 @@ function createTooltipDiv(tip) { } // Current values: weaknesses, resistances, immunities -function createTypeEffectivenessWrapper(typeEffectivenesses) { +function createTypeEffectivenessWrapper(typeEffectivenesses, typeEffectivenessDetailed = {}) { + console.log(typeEffectivenesses) + console.log(typeEffectivenessDetailed) + console.log(typeEffectivenessDetailed.cssClasses) + let typesHTML = ` ${Object.keys(typeEffectivenesses).map((effectiveness) => { if (typeEffectivenesses[effectiveness].length === 0) return '' @@ -166,12 +170,14 @@ function createTypeEffectivenessWrapper(typeEffectivenesses) {
${typeEffectivenesses[effectiveness].map((type, counter) => ` + ${/* The current html structure requires to wrap every third element in a div, the implementation here gets a bit ugly. */''} ${((counter + 1) % 3 === 1) ? `
` : ''} -
+
${/* Closing div, after every third element or when the arrays max length is reached. */''} ${((counter + 1) % 3 === 0) || ((counter + 1) === typeEffectivenesses[effectiveness].length) ? @@ -186,6 +192,14 @@ function createTypeEffectivenessWrapper(typeEffectivenesses) { return typesHTML } +function getTypeEffectivenessCssClass(type, typeEffectivenessDetailed) { + try { + return typeEffectivenessDetailed.cssClasses[type] + } catch (error) { + return '' + } +} + function createTooltipDiv(tip) { const tooltipHtml = `
${tip}
@@ -672,7 +686,7 @@ async function updateSidebarCards(partyID, sessionData, pokemonData) {
- ${createTypeEffectivenessWrapper(pokemon.typeEffectiveness)} + ${createTypeEffectivenessWrapper(pokemon.typeEffectiveness, pokemon.typeEffectivenessDetailed)}
diff --git a/content/util_classes/pokemonMapper.util.js b/content/util_classes/pokemonMapper.util.js index 9952e47..f224a6c 100644 --- a/content/util_classes/pokemonMapper.util.js +++ b/content/util_classes/pokemonMapper.util.js @@ -107,6 +107,24 @@ class PokemonMapperClass{ return {} } + static async #getPokemonTypeEffectivenessDetailed($this, id) { + const types = await PokemonMapperClass.#getPokeType(id); + // ignore single type pokemon + if (types && (types[1] !== 'undefined')) { + const { weaknesses, resistances, immunities, cssClasses } = await PokemonMapperClass.#calculateTypeEffectivenessDetailed($this, types); + return { + 'weaknesses': weaknesses, + 'resistances': resistances, + 'immunities': immunities, + 'cssClasses' : cssClasses + } + } + else { + return { weaknesses : {}, resistances : {}, immunities : {} , cssClasses : {} } + } + return { } + } + async getTypeEffectiveness(type) { try { const response = await fetch(`https://pokeapi.co/api/v2/type/${type}`); @@ -118,6 +136,115 @@ class PokemonMapperClass{ } } + /* + Quick and dirty function to get type weaknesses for dual types, including x4 and x0.25 dmg multipliers. + */ + static async #calculateTypeEffectivenessDetailed($this, types) { + const typesInPokemondbOrder = [ + "normal", + "fire", + "water", + "electric", + "grass", + "ice", + "fighting", + "poison", + "ground", + "flying", + "psychic", + "bug", + "rock", + "ghost", + "dragon", + "dark", + "steel", + "fairy", + "stellar" + ] + + const _ = 1; + const h = 1 / 2; + + // matrix of types against other types in pokemonDB order + // https://pokemondb.net/type + // taken from https://github.com/wavebeem/pkmn.help/blob/master/src/misc/data-matchups.ts + const genDefault = [ + [_, _, _, _, _, _, _, _, _, _, _, _, h, 0, _, _, h, _, _], + [_, h, h, _, 2, 2, _, _, _, _, _, 2, h, _, h, _, 2, _, _], + [_, 2, h, _, h, _, _, _, 2, _, _, _, 2, _, h, _, _, _, _], + [_, _, 2, h, h, _, _, _, 0, 2, _, _, _, _, h, _, _, _, _], + [_, h, 2, _, h, _, _, h, 2, h, _, h, 2, _, h, _, h, _, _], + [_, h, h, _, 2, h, _, _, 2, 2, _, _, _, _, 2, _, h, _, _], + [2, _, _, _, _, 2, _, h, _, h, h, h, 2, 0, _, 2, 2, h, _], + [_, _, _, _, 2, _, _, h, h, _, _, _, h, h, _, _, 0, 2, _], + [_, 2, _, 2, h, _, _, 2, _, 0, _, h, 2, _, _, _, 2, _, _], + [_, _, _, h, 2, _, 2, _, _, _, _, 2, h, _, _, _, h, _, _], + [_, _, _, _, _, _, 2, 2, _, _, h, _, _, _, _, 0, h, _, _], + [_, h, _, _, 2, _, h, h, _, h, 2, _, _, h, _, 2, h, h, _], + [_, 2, _, _, _, 2, h, _, h, 2, _, 2, _, _, _, _, h, _, _], + [0, _, _, _, _, _, _, _, _, _, 2, _, _, 2, _, h, _, _, _], + [_, _, _, _, _, _, _, _, _, _, _, _, _, _, 2, _, h, 0, _], + [_, _, _, _, _, _, h, _, _, _, 2, _, _, 2, _, h, _, h, _], + [_, h, h, h, _, 2, _, _, _, _, _, _, 2, _, _, _, h, 2, _], + [_, h, _, _, _, _, 2, h, _, _, _, _, _, _, 2, 2, h, _, _], + [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], + ]; + + let type1 = types[0] + let type2 = types[1] + let primaryIndex = typesInPokemondbOrder.indexOf(type1) + let secondaryIndex = typesInPokemondbOrder.indexOf(type2) + + //let results = { defenderPair : [type1, type2], immune : [], normal : [], half : [], quarter : [], double : [], quadrupel : [] } + let weaknesses = { 'normal' : [], 'double' : [] } + let resistances = { 'normal' : [], 'double' : [] } + let immunities = { 'normal' : [] } + let cssClasses = {} + //const typeEffectivenessObj = {} + + typesInPokemondbOrder.forEach((attackerType, i) => { + let defenderType_1 = genDefault[i][primaryIndex] + let defenderType_2 = genDefault[i][secondaryIndex] + + // at least 1 type is immune => immune + if (defenderType_1 == 0 || defenderType_2 == 0) { + immunities.normal.push(attackerType) + cssClasses[attackerType] = 'no-dmg' + return + } + // both types are weak => quadrupel dmg + else if ((defenderType_1 == 2 && defenderType_2 == 2)) { + weaknesses.double.push(attackerType) + cssClasses[attackerType] = 'super-dmg' + } + // one type is weak, the other takes normal dmg => double dmg + else if ((defenderType_1 == 2 && defenderType_2 == 1) || (defenderType_2 == 2 && defenderType_1 == 1)) { + weaknesses.normal.push(attackerType) + cssClasses[attackerType] = 'double-dmg' + } + // one type is weak, the other resists (half) => normal dmg + else if ((defenderType_1 == 2 && defenderType_2 == h) || (defenderType_2 == 2 && defenderType_1 == h)) { + // for the moment don't return, default dmg not being used + } + // both types take normal dmg => normal dmg + else if (defenderType_1 == _ && defenderType_2 == _) { + // for the moment don't return, default dmg not being used + } + // one type resists, the other takes normal dmg => half dmg + else if ((defenderType_1 == h && defenderType_2 == _) || (defenderType_2 == h && defenderType_1 == _)) { + resistances.normal.push(attackerType) + cssClasses[attackerType] = 'resist' + } + // both types resist (half) => quarter dmg + else if (defenderType_1 == h && defenderType_2 == h) { + resistances.double.push(attackerType) + cssClasses[attackerType] = 'super-resist' + } + }); + + return { weaknesses, resistances, immunities, cssClasses }; + } + static async #calculateTypeEffectiveness($this, types) { const typeEffectiveness = await Promise.all(types.map(type => $this.getTypeEffectiveness(type))); if (typeEffectiveness.some(data => data === null)) { @@ -232,6 +359,7 @@ class PokemonMapperClass{ const pokemonPromises = pokemonArray.map(async (pokemon) => { const pokemonId = $this.I2P[$this.convertPokemonId(pokemon.species)].toLocaleLowerCase(); const typeEffectiveness = await PokemonMapperClass.#getPokemonTypeEffectiveness($this, pokemonId); + const typeEffectivenessDetailed = await PokemonMapperClass.#getPokemonTypeEffectivenessDetailed($this, pokemonId); let basePokemon = $this.findBasePokemon($this.I2P[pokemon.species]); let name = $this.getPokemonName(pokemon); return { @@ -242,6 +370,12 @@ class PokemonMapperClass{ resistances: Array.from(typeEffectiveness.resistances), immunities: Array.from(typeEffectiveness.immunities), }, + typeEffectivenessDetailed: { + weaknesses: typeEffectivenessDetailed.weaknesses, + resistances: typeEffectivenessDetailed.resistances, + immunities: typeEffectivenessDetailed.immunities, + cssClasses: typeEffectivenessDetailed.cssClasses, + }, ivs: pokemon.ivs, ability: await $this.getPokemonAbility(pokemon.species, pokemon.abilityIndex, pokemon.fusionSpecies, pokemon.fusionAbilityIndex), nature: $this.I2N[pokemon.nature], diff --git a/styles.css b/styles.css index 4718be9..74862bb 100644 --- a/styles.css +++ b/styles.css @@ -154,6 +154,25 @@ body.sidebar-Bottom { ); } +.pokemon-weaknesses .super-dmg, .pokemon-weaknesses .super-resist, +.pokemon-resistances .super-dmg, .pokemon-resistances .super-resist, +.pokemon-immunities .super-dmg, .pokemon-immunities .super-resist { + border: solid 1px white; + animation: pulsate 1s ease-out; + animation-iteration-count: infinite; + opacity: 1; +} +@keyframes pulsate { + 0% {-webkit-transform: scale(0.9, 0.9); opacity: 0.8;} + 50% {opacity: 1.0;} + 100% {-webkit-transform: scale(1.1, 1.1); opacity: 0.8;} +} +@keyframes opacityPulse { + 0% {opacity: 0.5;} + 50% {opacity: 1.0;} + 100% {opacity: 0.5;} +} + /* */ .allies-team { From 69aef8653f591a6067df0957008ac01c5707adfa Mon Sep 17 00:00:00 2001 From: Eruyome Date: Sat, 25 May 2024 15:55:03 +0200 Subject: [PATCH 15/78] Reworked the sidebar html and added a bottom panel (shows weather, empty otherwise) --- content/content.js | 210 +++++++++++++++++++++++---------- styles.css | 287 +++++++++++++++++++++++++++++++++------------ 2 files changed, 364 insertions(+), 133 deletions(-) diff --git a/content/content.js b/content/content.js index f157e01..ca50815 100644 --- a/content/content.js +++ b/content/content.js @@ -46,16 +46,22 @@ let wrapperDivPositions = { } } -function createEnemyDiv() { +function createEnemyDiv(showSidebar = false) { const enemies = document.createElement("div"); enemies.className = 'enemy-team' + if (showSidebar) { + enemies.className = 'hidden' + } enemies.id = "enemies"; return enemies; } -function createAlliesDiv() { +function createAlliesDiv(showSidebar = false) { const allies = document.createElement("div"); allies.className = 'allies-team' + if (showSidebar) { + allies.className = 'hidden' + } allies.id = "allies"; return allies; } @@ -154,10 +160,6 @@ function createTooltipDiv(tip) { // Current values: weaknesses, resistances, immunities function createTypeEffectivenessWrapper(typeEffectivenesses, typeEffectivenessDetailed = {}) { - console.log(typeEffectivenesses) - console.log(typeEffectivenessDetailed) - console.log(typeEffectivenessDetailed.cssClasses) - let typesHTML = ` ${Object.keys(typeEffectivenesses).map((effectiveness) => { if (typeEffectivenesses[effectiveness].length === 0) return '' @@ -282,7 +284,7 @@ async function createPokemonCardDiv(cardId, pokemon) { // getPokemonIcon(pokemon); let pokemonImageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; const opacitySlider = createOpacitySliderDiv(cardId, wrapperDivPositions[cardId].opacity, opacityRangeMin, opacityRangeMax); - const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness); + const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness, pokemon.typeEffectivenessDetailed); let cardHTML = `
@@ -525,7 +527,7 @@ async function createPokemonCardDiv_minified(cardId, pokemon) { let opacityRangeMax = 100; let pokemonImageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`; const opacitySlider = createOpacitySliderDiv(cardId, wrapperDivPositions[cardId].opacity, opacityRangeMin, opacityRangeMax); - const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness); + const typeEffectivenessHTML = createTypeEffectivenessWrapper(pokemon.typeEffectiveness, pokemon.typeEffectivenessDetailed); let ivsGeneratedHTML = generateIVsHTML(pokemon, dexIvs); //${opacitySlider.html} //
@@ -570,14 +572,14 @@ async function createPokemonCardDiv_minified(cardId, pokemon) { return cardObj } -function createWrapperDiv(divId) { +function createWrapperDiv(divId, showSidebar) { const oldDiv = document.getElementById(divId) if (oldDiv) { wrapperDivPositions[divId].top = oldDiv.style.top; wrapperDivPositions[divId].left = oldDiv.style.left; oldDiv.remove(); } - const newDiv = divId === 'enemies' ? createEnemyDiv() : createAlliesDiv() + const newDiv = divId === 'enemies' ? createEnemyDiv(showSidebar) : createAlliesDiv(showSidebar) enableDragElement(newDiv) newDiv.style.top = wrapperDivPositions[divId].top newDiv.style.left = wrapperDivPositions[divId].left @@ -619,7 +621,7 @@ async function chooseCardType(divId, pokemon, minified){ async function createCardsDiv(divId, pokemonData, pokemonIndex) { const pokemon = pokemonData[pokemonIndex] let extensionSettings = await Utils.LocalStorage.getExtensionSettings(); - let newDiv = createWrapperDiv(divId); + let newDiv = createWrapperDiv(divId, extensionSettings.showSidebar); return await chooseCardType(divId, pokemon, extensionSettings.showMinified).then(async (cardObj) =>{ const buttonsObj = createArrowButtonsDiv(divId, "↑", "↓", extensionSettings.showMinified); @@ -647,79 +649,107 @@ async function createCardsDiv(divId, pokemonData, pokemonIndex) { function createSidebar() { const sidebarHtml = `
- ` + const bottomPanelHtml = ` + + ` + document.body.insertAdjacentHTML("afterbegin", sidebarHtml) + document.body.insertAdjacentHTML("beforeend", bottomPanelHtml) +} + +function createSidebarTypeEffectivenessWrapper(typeEffectivenesses, typeEffectivenessDetailed = {}) { + let typesHTML = ` + ${Object.keys(typeEffectivenesses).map((effectiveness) => { + if (typeEffectivenesses[effectiveness].length === 0) return '' + + return ` +
+ ${typeEffectivenesses[effectiveness].map((type, counter) => ` +
+ `).join('')} +
+ `}).join('')} + ` + return typesHTML } /* Updates party information for both sides (allies, enemies) in the sidebar. */ async function updateSidebarCards(partyID, sessionData, pokemonData) { - const sidebarPartyElement = document.getElementById(`sidebar-${partyID}-box`) - const extensionSettings = await Utils.LocalStorage.getExtensionSettings() + const sidebarPartyElement = document.getElementById(`sidebar-${partyID}-box`) let savedData = Utils.LocalStorage.getPlayerData() - let dexData = savedData["dexData"] - - sidebarPartyElement.replaceChildren(); - - let partyHeader = ''; - if (extensionSettings.showParty && (partyID == 'enemies')) { - partyHeader = `` - } - else if (extensionSettings.showEnemies && (partyID == 'allies')) { - partyHeader = `` - } + let dexData = savedData["dexData"] - let partyHtml = ` - ${partyHeader} + sidebarPartyElement.replaceChildren(); + let partyWrapperHtml = ` +
${pokemonData.pokemon.map((pokemon, counter) => ` -