diff --git a/README.md b/README.md index 0a520bb..be17998 100644 --- a/README.md +++ b/README.md @@ -50,17 +50,18 @@ You may also [join my Discord server](https://discord.gg/nfbT8zJSkd) (can also c 9. [**Script Fixer Upper**](#script-fixer-upper) 10. [**Script Handler** (Included in desktop/app.asar)](#script-manager) # Custom Scripts -1. [**Auto Quest Completer** ](#auto-quest-completer) -9. [**Auto Safari Zone** ](#auto-safari-zone) -2. [**Catch Speed Adjuster** ](#catch-speed-adjuster) -3. [**Challenge Mode Changer** ](#challenge-mode-changer) -4. [**Discord Code Generator** ](#discord-code-generator) -5. [**Infinite Seasonal Events** ](#infinite-seasonal-events) -6. [**Oak Items Unlimited** ](#oak-iems-unlimited) -7. [**Omega Protein Gains** ](#omega-protein-gains) -7. [**Overnight Berry Growth** ](#overnight-berry-growth) -8. [**Perky Pokerus Pandemic** ](#perky-pokerus-pandemic) -9. [**Simple Weather Changer** ](#simple-weather-changer) +1. [**Auto Keep MissingNo** ](#auto-keep-missingno) +2. [**Auto Quest Completer** ](#auto-quest-completer) +3. [**Auto Safari Zone** ](#auto-safari-zone) +4. [**Catch Speed Adjuster** ](#catch-speed-adjuster) +5. [**Challenge Mode Changer** ](#challenge-mode-changer) +6. [**Discord Code Generator** ](#discord-code-generator) +7. [**Infinite Seasonal Events** ](#infinite-seasonal-events) +8. [**Oak Items Unlimited** ](#oak-iems-unlimited) +9. [**Omega Protein Gains** ](#omega-protein-gains) +10. [**Overnight Berry Growth** ](#overnight-berry-growth) +11. [**Perky Pokerus Pandemic** ](#perky-pokerus-pandemic) +12. [**Simple Weather Changer** ](#simple-weather-changer) ```diff - Note: Please backup your saves before using any and all scripts that would be here!!! @@ -325,6 +326,16 @@ This script is only compatible with the desktop client. For detailed instruction
+ +## [Custom] Auto Keep MissingNo (autokeepmissingno.user.user.js) (One-Click Install) + +This script lets you keep your MissingNo, which is automatically deleted when your pokeclicker save is updated. +All the MissingNo's information (nickname, category, exp, etc.), the vitamins used and the object held are kept. + +The script also allows you to give yourself a MissingNo, from the Save / Enter Code menu you need to type missingNo in the Code entry then claim to unlock it. + +
+ ## [Custom] Auto Quest Completer (autoquestcompleter.user.js) (One-Click Install) This script automatically completes and starts quests and can be toggled with this button:
diff --git a/custom/autokeepmissingno.user.js b/custom/autokeepmissingno.user.js new file mode 100644 index 0000000..5b27305 --- /dev/null +++ b/custom/autokeepmissingno.user.js @@ -0,0 +1,308 @@ +/* eslint-disable no-use-before-define */ +/* eslint-disable max-len */ +/* eslint-disable no-undef */ +// ==UserScript== +// @name [Pokeclicker] Auto Keep MissingNo +// @namespace Pokeclicker Scripts +// @author Skelman (Credit: Ephenia) +// @description Keeps your missingno when deleted during pokéclicker updates. +// @copyright https://github.com/hippolythe +// @license GPL-3.0 License +// @version 1.0.0 + +// @homepageURL https://github.com/Ephenia/Pokeclicker-Scripts/ +// @supportURL https://github.com/Ephenia/Pokeclicker-Scripts/issues +// @downloadURL https://raw.githubusercontent.com/Ephenia/Pokeclicker-Scripts/master/custom/autokeepmissingno.user.js +// @updateURL https://raw.githubusercontent.com/Ephenia/Pokeclicker-Scripts/master/custom/autokeepmissingno.user.js + +// @match https://www.pokeclicker.com/ +// @icon https://www.google.com/s2/favicons?domain=pokeclicker.com +// @grant unsafeWindow +// @run-at document-idle +// ==/UserScript== + +document.addEventListener("click", function (event) { + const trainerCard = event.target.closest(".trainer-card"); + + if (trainerCard !== null && trainerCard.dataset !== null) { + const key = trainerCard.dataset.key; + const rawData = localStorage.getItem(`save${key}`); + const saveData = JSON.parse(rawData); + const missingNoToKeep = saveData.party.caughtPokemon.find(pokemon => pokemon.id === 0); + + if (missingNoToKeep) { + setTimeout(function () { + const hasMissingNoBeenDeleted = App.game.party.getPokemonByName('MissingNo.') === undefined ? true : false; + + if (hasMissingNoBeenDeleted) { + const isShiny = missingNoToKeep[5] === undefined || missingNoToKeep[5] === false ? false : true; + App.game.party.gainPokemonById(0, isShiny); + const newMissingNo = App.game.party.getPokemonByName('MissingNo.'); + createPartyPokemon(newMissingNo, missingNoToKeep); + overrideHatcheryFunction(newMissingNo); + } + }, 5000); + } + } +}); + +document.getElementById("redeemable-code-input").addEventListener('change', function() { + if (this.value.toLowerCase() === "missingno" || this.value.toLowerCase() === "missingno.") { + App.game.party.gainPokemonById(0, false); + } +}); + +function createPartyPokemon(newMissingNo, missingNoToKeep) { + getVitamins(newMissingNo, missingNoToKeep[2]); + getHeldItem(newMissingNo, missingNoToKeep[10]); + + newMissingNo.attackBonusPercent = missingNoToKeep[0]; + newMissingNo.attackBonusAmount = missingNoToKeep[1]; + newMissingNo.exp = missingNoToKeep[3]; + newMissingNo.category = missingNoToKeep[6]; + newMissingNo.pokerus = missingNoToKeep[8]; + newMissingNo.effortPoints = missingNoToKeep[9]; + newMissingNo.nickname = missingNoToKeep[12]; +} + +function getVitamins(newMissingNo, vitaminsUsed) { + const proteinGets = player.itemList.Protein(); + const calciumGets = player.itemList.Calcium(); + const carbosGets = player.itemList.Carbos(); + + player.itemList.Protein(proteinGets + vitaminsUsed[0]); + player.itemList.Calcium(calciumGets + vitaminsUsed[1]); + player.itemList.Carbos(carbosGets + vitaminsUsed[2]); + + newMissingNo.useVitamin(GameConstants.VitaminType.Protein, vitaminsUsed[0]); + newMissingNo.useVitamin(GameConstants.VitaminType.Calcium, vitaminsUsed[1]); + newMissingNo.useVitamin(GameConstants.VitaminType.Carbos, vitaminsUsed[2]); +} + +function getHeldItem(newMissingNo, heldItemName) { + if (heldItemName !== undefined) { + const heldItem = new HeldItem( + heldItemName, + 0, + GameConstants.Currency.money, { + maxAmount: 1 + }, + '', + '', + GameConstants.Region.kanto, + (pokemon) => true + ); + + if (heldItem.name !== undefined) { + const heldItemQuantity = player.itemList[heldItem.name](); + player.itemList[heldItem.name](heldItemQuantity + 1); + newMissingNo.giveHeldItem(heldItem); + } + } +} + +function initkeepMissingNo() { + PartyController.getVitaminFilteredList = overridePartyControllerMethods(PartyController.getVitaminFilteredList.toString()); + PartyController.getHeldItemFilteredList = overridePartyControllerMethods(PartyController.getHeldItemFilteredList.toString()); + + if (App.game.party.caughtPokemon[0]) { + overrideHatcheryFunction(App.game.party.caughtPokemon[0]); + } +} + +function overridePartyControllerMethods(functionToOverride) { + const patchedFunction = functionToOverride.replace(/if\s*\(\s*pokemon\.id\s*<=\s*0\s*\)\s*\{\s*return\s*false;\s*\}/, ''); + const braceStart = patchedFunction.indexOf('{'); + const braceEnd = patchedFunction.lastIndexOf('}'); + let body = patchedFunction.slice(braceStart + 1, braceEnd).split('\n'); + + return (new Function(body.join('\n'))); +} + +function overrideHatcheryFunction(missingNo) { + delete missingNo.matchesHatcheryFilters; + + missingNo.matchesHatcheryFilters = ko.pureComputed(function () { + // Check if search matches englishName or displayName + const nameFilterSetting = Settings.getSetting('breedingNameFilter'); + if (nameFilterSetting.observableValue() != '') { + const nameFilter = nameFilterSetting.regex(); + const displayName = PokemonHelper.displayName(this.name)(); + const partyName = this.displayName; + if (!nameFilter.test(displayName) && !nameFilter.test(this.name) && !(partyName != undefined && nameFilter.test(partyName))) { + return false; + } + } + + // Check if search matches species number + const idFilter = Settings.getSetting('breedingIDFilter').observableValue(); + if (idFilter > -1 && idFilter != Math.floor(this.id)) { + return false; + } + + // Check based on categories + const categoryFilter = Settings.getSetting('breedingCategoryFilter').observableValue(); + // Categorized only + if (categoryFilter == -2 && this.isUncategorized()) { + return false; + } + // Selected category + if (categoryFilter >= 0 && !this.category.includes(categoryFilter)) { + return false; + } + + // Check based on shiny status + const shinyFilter = Settings.getSetting('breedingShinyFilter').observableValue(); + if (shinyFilter >= 0 && +this.shiny !== shinyFilter) { + return false; + } + + // Check based on native region + const unlockedRegionsMask = (2 << player.highestRegion()) - 1; + const regionFilterMask = Settings.getSetting('breedingRegionFilter').observableValue() & unlockedRegionsMask; + if (regionFilterMask !== unlockedRegionsMask) { + const nativeRegion = PokemonHelper.calcNativeRegion(this.name); + // With the region filter active, regionless pokemon should be shown only if no regions are selected + const nativeRegionInFilter = nativeRegion !== GameConstants.Region.none ? + (1 << nativeRegion) & regionFilterMask : + regionFilterMask === 0; + if (!nativeRegionInFilter) { + return false; + } + } + + // Check based on Pokerus status + const pokerusFilter = Settings.getSetting('breedingPokerusFilter').observableValue(); + if (pokerusFilter > -1 && this.pokerus !== pokerusFilter) { + return false; + } + + const uniqueTransformationFilter = Settings.getSetting('breedingUniqueTransformationFilter').observableValue(); + const pokemon = PokemonHelper.getPokemonById(this.id); + // Only Base Pokémon with Mega available + if (uniqueTransformationFilter == 'mega-available' && !PokemonHelper.hasMegaEvolution(pokemon.name)) { + return false; + } + // Only Base Pokémon without Mega Evolution + if (uniqueTransformationFilter == 'mega-unobtained' && !PokemonHelper.hasUncaughtMegaEvolution(pokemon.name)) { + return false; + } + // Only Mega Pokémon + if (uniqueTransformationFilter == 'mega-evolution' && !PokemonHelper.isMegaEvolution(pokemon.name)) { + return false; + } + + // Check to exclude alternate forms + const hideAltFilter = Settings.getSetting('breedingHideAltFilter').observableValue(); + if (hideAltFilter && !Number.isInteger(pokemon.id)) { + // Don't exclude alt forms native to a different region, as they're considered a main form for that region's progression + const nativeRegion = PokemonHelper.calcNativeRegion(this.name); + const hasBaseFormInSameRegion = pokemonList.some((p) => Math.floor(p.id) == Math.floor(pokemon.id) && p.id < pokemon.id && PokemonHelper.calcNativeRegion(p.name) == nativeRegion); + if (hasBaseFormInSameRegion) { + return false; + } + } + + // Check if either of the types match + const type1 = Settings.getSetting('breedingType1Filter').observableValue(); + const type2 = Settings.getSetting('breedingType2Filter').observableValue(); + + if (type1 !== null || type2 !== null) { + const { type: types } = pokemonMap[this.name]; + if ([type1, type2].includes(PokemonType.None)) { + const type = (type1 == PokemonType.None) ? type2 : type1; + if (!BreedingController.isPureType(this, type)) { + return false; + } + } else if ((type1 !== null && !types.includes(type1)) || (type2 !== null && !types.includes(type2))) { + return false; + } + } + + return true; + }, missingNo); +} + +function loadSetting(key, defaultVal) { + var val; + try { + val = JSON.parse(localStorage.getItem(key)); + if (val == null || typeof val !== typeof defaultVal) { + throw new Error; + } + } catch { + val = defaultVal; + localStorage.setItem(key, defaultVal); + } + return val; +} + +function loadEpheniaScript(scriptName, initFunction, priorityFunction) { + function reportScriptError(scriptName, error) { + console.error(`Error while initializing '${scriptName}' userscript:\n${error}`); + Notifier.notify({ + type: NotificationConstants.NotificationOption.warning, + title: scriptName, + message: `The '${scriptName}' userscript crashed while loading. Check for updates or disable the script, then restart the game.\n\nReport script issues to the script developer, not to the Pokéclicker team.`, + timeout: GameConstants.DAY, + }); + } + const windowObject = window; + // Inject handlers if they don't exist yet + if (windowObject.epheniaScriptInitializers === undefined) { + windowObject.epheniaScriptInitializers = {}; + const oldInit = Preload.hideSplashScreen; + var hasInitialized = false; + + // Initializes scripts once enough of the game has loaded + Preload.hideSplashScreen = function (...args) { + var result = oldInit.apply(this, args); + if (App.game && !hasInitialized) { + // Initialize all attached userscripts + Object.entries(windowObject.epheniaScriptInitializers).forEach(([scriptName, initFunction]) => { + try { + initFunction(); + } catch (e) { + reportScriptError(scriptName, e); + } + }); + hasInitialized = true; + } + return result; + } + } + + // Prevent issues with duplicate script names + if (windowObject.epheniaScriptInitializers[scriptName] !== undefined) { + console.warn(`Duplicate '${scriptName}' userscripts found!`); + Notifier.notify({ + type: NotificationConstants.NotificationOption.warning, + title: scriptName, + message: `Duplicate '${scriptName}' userscripts detected. This could cause unpredictable behavior and is not recommended.`, + timeout: GameConstants.DAY, + }); + let number = 2; + while (windowObject.epheniaScriptInitializers[`${scriptName} ${number}`] !== undefined) { + number++; + } + scriptName = `${scriptName} ${number}`; + } + // Add initializer for this particular script + windowObject.epheniaScriptInitializers[scriptName] = initFunction; + // Run any functions that need to execute before the game starts + if (priorityFunction) { + $(document).ready(() => { + try { + priorityFunction(); + } catch (e) { + reportScriptError(scriptName, e); + // Remove main initialization function + windowObject.epheniaScriptInitializers[scriptName] = () => null; + } + }); + } +} + +if (!App.isUsingClient || localStorage.getItem('autokeepmissingno') === 'true') { + loadEpheniaScript('autokeepmissingno', initkeepMissingNo); +} \ No newline at end of file