// ==UserScript== // @name DH2 replay sprites // @version 1.04 // @description Fetch alternative image sources when default ones fail. // @match https://replay.pokemonshowdown.com/* // @grant none // ==/UserScript== (async function() { var dh2Paths = await getDh2Paths(); var modRegex = /dragonheaven-([^-/]+)/; var modRegex2 = /replay\.pokemonshowdown\.com\/([^-\s?\/]+)/; var petMod = window.location.href.match(modRegex2)[1] === 'dragonheaven' ? window.location.href.match(modRegex)[1] : window.location.href.match(modRegex2)[1]; console.log(petMod); const suffixes = ['ou', 'ubers', 'uu', 'nu', 'lc']; for (let suffix of suffixes) { switch (petMod) { case "gen9fusionevolution": case "gen9fusionevolutionuu": case "gen9fusionevolutioncorruptcouncil": petMod = "gen9fe"; break; case "gen8m4aounatdex": petMod = "m4ag9"; break; case "gen1kantoexpansionpakou": case "gen1kantoexpansionpakubers": case "gen1kantoexpansionpakuu": petMod = "gen1expansionpack"; break; case "gen2johtoexpansionpakubers": case "gen2johtoexpansionpakalphaou": petMod = "gen2expansionpack"; break; case "gen9balls": petMod = "balls"; break; case "gen9scootopia": petMod = "scootopia"; break; case "gen9maadowrvgc": case "gen9maadowrsingles": petMod = "maadowr"; break; default: if (petMod.endsWith(suffix)) { petMod = petMod.slice(0, -suffix.length); petMod = petMod.replace('gen9', ''); } break; } } // Replace images once the initial paths are loaded. imgReplace(); // Observe for new images loaded dynamically (e.g., via AJAX) const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.addedNodes && mutation.addedNodes.length > 0) { imgReplace(); } }); }); observer.observe(document.body, { childList: true, subtree: true }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['src'] }); async function getDh2Paths() { const url = 'https://api.github.com/repos/scoopapa/DH2/git/trees/934a0a1fedc7a136c13f22abc1e913695105f8a5'; try { const response = await fetch(url); const data = await response.json(); if (data.tree && Array.isArray(data.tree)) { const pathsAsArrays = data.tree.map(item => item.path); console.log(pathsAsArrays); return pathsAsArrays; } else { throw new Error('Invalid API response structure'); } } catch (error) { console.error('Error fetching data from Scoopapa\'s DH2 GitHub repository:', error); } } function imgReplace() { var images = [].slice.call(document.getElementsByTagName('img')); images.forEach(img => { img.onerror = function() { spriteReplace(img); } }); } function spriteReplace(img) { console.log('Attempting to replace sprite for image', img.src); img.dataset.retried = 'true'; console.log('Processing image for the first time:', img.src); let newSrc; const spriteGens = [1,2,3,4,5]; const tierGen = spriteGens.filter((gen) => img.src.includes('gen' + gen))[0] || 5; if (img.src.includes('/sprites/gen' + tierGen + '/')) { newSrc = img.src.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/front/'); console.log('New front sprite:', newSrc); } else if (img.src.includes('/sprites/gen' + tierGen + '-back/')) { newSrc = img.src.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '-back/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/back/'); console.log('New back sprite:', newSrc); } else if (img.src.includes('/sprites/gen' + tierGen + '-shiny/')) { newSrc = img.src.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '-shiny/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/front-shiny/'); console.log('New front-shiny sprite:', newSrc); } else if (img.src.includes('/sprites/gen' + tierGen + '-back-shiny/')) { newSrc = img.src.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '-back-shiny/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/back-shiny/'); console.log('New back-shiny sprite:', newSrc); } else { newSrc = 'https://play.pokemonshowdown.com/sprites/gen' + tierGen + '/substitute.png'; } if (newSrc) { img.src = newSrc; } } const originalAnimTransform = window.PokemonSprite.prototype.animTransform; window.PokemonSprite.prototype.animTransform = function(pokemon, isCustomAnim, isPermanent) { console.log('animTransform called for pokemon:', pokemon.name); // Get the new sprite data let sp = window.Dex.getSpriteData(pokemon, this.isFrontSprite, { gen: this.scene.gen, mod: this.scene.mod, }); const spriteGens = [1,2,3,4,5]; const tierGen = spriteGens.filter((gen) => sp.url.includes('gen' + gen))[0] || 5; // Check if the sprite URL needs to be replaced if (sp.url.includes('sprites/gen' + tierGen)) { if (sp.url.includes('/sprites/gen' + tierGen + '/')) { sp.url = sp.url.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/front/'); } else if (sp.url.includes('/sprites/gen' + tierGen + '-back/')) { sp.url = sp.url.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '-back/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/back/'); } else if (sp.url.includes('/sprites/gen' + tierGen + '-shiny/')) { sp.url = sp.url.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '-shiny/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/front-shiny/'); } else if (sp.url.includes('/sprites/gen' + tierGen + '-back-shiny/')) { sp.url = sp.url.replace('https://play.pokemonshowdown.com/sprites/gen' + tierGen + '-back-shiny/', 'https://raw.githubusercontent.com/scoopapa/dh2/master/data/mods/' + petMod + '/sprites/back-shiny/'); } else { sp.url = 'https://play.pokemonshowdown.com/sprites/gen' + tierGen + '/substitute.png'; } this.sp = sp; console.log('Updated sprite URL in animTransform:', sp.url); // Update the image element directly let $newEl = window.$(''); $newEl.css(this.scene.pos({ x: this.x, y: this.y, z: this.z, yscale: 0, xscale: 0, opacity: 0, }, sp)); if (this.$el) { this.$el.replaceWith($newEl); this.$el = $newEl; this.$el.animate(this.scene.pos({ x: this.x, y: this.y, z: this.z, opacity: 1, }, sp), 300); this.scene.wait(500); } } else { console.log('custom transform sprite not found. Using default animation.'); originalAnimTransform.apply(this, arguments); } }; })();