From 4e9bd2807b26f1cd08046c4b30129ad56edb487e Mon Sep 17 00:00:00 2001 From: hippolythe guiffant Date: Sat, 24 May 2025 12:00:52 +0200 Subject: [PATCH 1/5] Allow you to keep your missingno MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keeps your missingno when deleted during pokéclicker updates. --- custom/autokeepmissingno.user.js | 179 +++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 custom/autokeepmissingno.user.js diff --git a/custom/autokeepmissingno.user.js b/custom/autokeepmissingno.user.js new file mode 100644 index 0000000..44fe0e7 --- /dev/null +++ b/custom/autokeepmissingno.user.js @@ -0,0 +1,179 @@ +/* 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); + } + }, 5000); + } + } +}); + +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) { + 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() {} + +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 From 1885c2cd53a7cb55a0bbd9338b5de6de3f7c9081 Mon Sep 17 00:00:00 2001 From: hippolythe guiffant Date: Sat, 24 May 2025 12:28:07 +0200 Subject: [PATCH 2/5] Update README.md --- README.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 0a520bb..b1b6d1c 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,14 @@ 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. + +
+ ## [Custom] Auto Quest Completer (autoquestcompleter.user.js) (One-Click Install) This script automatically completes and starts quests and can be toggled with this button:
From de23c13a3137c9da009eabf586699c8b22bde9fe Mon Sep 17 00:00:00 2001 From: hippolythe guiffant Date: Wed, 16 Jul 2025 19:28:26 +0200 Subject: [PATCH 3/5] update script to allow missingNo in hatchery and gave it items and vitamins update script to allow missingNo in hatchery and gave it items and vitamins --- custom/autokeepmissingno.user.js | 159 +++++++++++++++++++++++++++---- 1 file changed, 141 insertions(+), 18 deletions(-) diff --git a/custom/autokeepmissingno.user.js b/custom/autokeepmissingno.user.js index 44fe0e7..545e544 100644 --- a/custom/autokeepmissingno.user.js +++ b/custom/autokeepmissingno.user.js @@ -21,7 +21,7 @@ // @run-at document-idle // ==/UserScript== -document.addEventListener("click", function(event) { +document.addEventListener("click", function (event) { const trainerCard = event.target.closest(".trainer-card"); if (trainerCard !== null && trainerCard.dataset !== null) { @@ -31,7 +31,7 @@ document.addEventListener("click", function(event) { const missingNoToKeep = saveData.party.caughtPokemon.find(pokemon => pokemon.id === 0); if (missingNoToKeep) { - setTimeout(function() { + setTimeout(function () { const hasMissingNoBeenDeleted = App.game.party.getPokemonByName('MissingNo.') === undefined ? true : false; if (hasMissingNoBeenDeleted) { @@ -39,6 +39,7 @@ document.addEventListener("click", function(event) { App.game.party.gainPokemonById(0, isShiny); const newMissingNo = App.game.party.getPokemonByName('MissingNo.'); createPartyPokemon(newMissingNo, missingNoToKeep); + overrideHatcheryFunction(newMissingNo); } }, 5000); } @@ -73,26 +74,148 @@ function getVitamins(newMissingNo, vitaminsUsed) { } function getHeldItem(newMissingNo, heldItemName) { - const heldItem = new HeldItem( - heldItemName, - 0, - GameConstants.Currency.money, { + 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); + '', + '', + 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 initkeepMissingNo() {} +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; @@ -126,7 +249,7 @@ function loadEpheniaScript(scriptName, initFunction, priorityFunction) { var hasInitialized = false; // Initializes scripts once enough of the game has loaded - Preload.hideSplashScreen = function(...args) { + Preload.hideSplashScreen = function (...args) { var result = oldInit.apply(this, args); if (App.game && !hasInitialized) { // Initialize all attached userscripts From 41f71024a956aa9bf13618adc1ac5c19d02fbf10 Mon Sep 17 00:00:00 2001 From: hippolythe guiffant Date: Thu, 24 Jul 2025 22:40:21 +0200 Subject: [PATCH 4/5] Adds the possibility of giving yourself a missingNo from the discord code field --- custom/autokeepmissingno.user.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/custom/autokeepmissingno.user.js b/custom/autokeepmissingno.user.js index 545e544..5b27305 100644 --- a/custom/autokeepmissingno.user.js +++ b/custom/autokeepmissingno.user.js @@ -46,6 +46,12 @@ document.addEventListener("click", function (event) { } }); +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]); From 561e3dcffcc89f007d9af861dae0f17d2400f933 Mon Sep 17 00:00:00 2001 From: hippolythe guiffant Date: Thu, 24 Jul 2025 22:47:12 +0200 Subject: [PATCH 5/5] Readme update. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b1b6d1c..be17998 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,8 @@ This script is only compatible with the desktop client. For detailed instruction 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. +