// ==UserScript==
// @name Doppler, Fade, Fire & Ice, Case Hardened Highlighter
// @namespace http://tampermonkey.net/
// @version 1.5
// @description Pattern Icons
// @author 2klex
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const ICONS = {
doppler: {
sapphire: {
url: 'https://i.imgur.com/by6BOg9.png',
glow: '0 0 12px rgba(0, 153, 255, 0.8)'
},
ruby: {
url: 'https://i.imgur.com/BbUJ9hD.png',
glow: '0 0 12px rgba(255, 0, 64, 0.8)'
},
emerald: {
url: 'https://i.imgur.com/qBsxDft.png',
glow: '0 0 12px rgba(0, 255, 153, 0.8)'
},
blackpearl: {
url: 'https://i.imgur.com/atZUPhw.png',
glow: '0 0 12px rgba(102, 0, 204, 0.8)'
}
},
fade: {
'100': {
url: 'https://i.imgur.com/SwqnfNP.png',
glow: '0 0 12px rgba(255, 255, 102, 0.8)'
},
'80': {
url: 'https://i.imgur.com/ZxY4lMl.png',
glow: '0 0 12px rgba(255, 102, 204, 0.8)'
}
},
fireice: {
max: {
url: 'https://i.imgur.com/VkKwObR.png',
glow: '0 0 12px rgba(255, 85, 0, 0.8), 0 0 12px rgba(0, 128, 255, 0.8)'
}
},
casehardened: {
bg: {
url: 'https://i.imgur.com/6pDs0BO.png',
glow: '0 0 12px rgba(102, 178, 255, 0.8)'
},
gg: {
url: 'https://i.imgur.com/9U0L9ka.png',
glow: '0 0 12px rgba(255, 204, 0, 0.8)'
},
tier2: {
url: 'https://i.imgur.com/wufyb2f.png',
glow: '0 0 12px rgba(255, 102, 204, 0.8)'
},
tier3: {
url: 'https://i.imgur.com/gP7aiE2.png',
glow: '0 0 12px rgba(255, 140, 0, 0.8)'
},
tier4: {
url: 'https://i.imgur.com/2WXhwNe.png',
glow: '0 0 12px rgba(192, 192, 192, 0.8)'
}
}
};
function getVariantFromFilename(src) {
const lowered = src.toLowerCase();
// Doppler gems (normal)
if (lowered.includes('doppler')) {
if (lowered.includes('sapphire')) return { type: 'doppler', key: 'sapphire' };
if (lowered.includes('ruby')) return { type: 'doppler', key: 'ruby' };
if (lowered.includes('emerald')) return { type: 'doppler', key: 'emerald' };
if (lowered.includes('blackpearl') || lowered.includes('black_pearl')) return { type: 'doppler', key: 'blackpearl' };
}
// Handle known Doppler knives with _bp/_ruby/_sapphire but without "doppler"
const dopplerKnives = ['survival', 'paracord', 'nomad', 'skeleton'];
const baseName = lowered.split('/').pop() || ''; // get just filename
const knifeMatch = dopplerKnives.find(knife => baseName.startsWith(knife + '_'));
if (knifeMatch) {
if (baseName.includes('_bp')) return { type: 'doppler', key: 'blackpearl' };
if (baseName.includes('_ruby')) return { type: 'doppler', key: 'ruby' };
if (baseName.includes('_sapphire')) return { type: 'doppler', key: 'sapphire' };
}
// Fade %
if (lowered.match(/[_-]100\.png/)) return { type: 'fade', key: '100' };
if (lowered.match(/[_-]80\.png/)) return { type: 'fade', key: '80' };
// Fire & Ice
if (lowered.includes('_fi_max')) return { type: 'fireice', key: 'max' };
// Case Hardened
if (lowered.includes('_ch_bg')) return { type: 'casehardened', key: 'bg' };
if (lowered.includes('_ch_gg')) return { type: 'casehardened', key: 'gg' };
if (lowered.includes('_ch_tier2')) return { type: 'casehardened', key: 'tier2' };
if (lowered.includes('_ch_tier3')) return { type: 'casehardened', key: 'tier3' };
if (lowered.includes('_ch_tier4')) return { type: 'casehardened', key: 'tier4' };
return null;
}
function flagSkinImage(img) {
if (img.dataset.dopplerFlagged) return;
if (img.closest('.mantine-Modal-root')) return;
const src = img.src || img.dataset.src || '';
const variant = getVariantFromFilename(src);
if (!variant) return;
const wrapper = img.closest('.mantine-Card-root') || img.parentElement;
if (!wrapper) return;
const iconData = ICONS[variant.type][variant.key];
if (!iconData) return;
const icon = document.createElement('img');
icon.src = iconData.url;
icon.alt = variant.key;
icon.dataset.highlighterIcon = 'true';
icon.style.position = 'absolute';
icon.style.top = '8px';
icon.style.right = '8px'; // will be adjusted below
icon.style.width = '32px';
icon.style.height = '32px';
icon.style.zIndex = '10';
icon.style.pointerEvents = 'none';
icon.style.filter = `drop-shadow(${iconData.glow})`;
wrapper.style.position = 'relative';
wrapper.appendChild(icon);
// initial adjustment for this card
adjustIconPositionForCard(wrapper);
img.dataset.dopplerFlagged = 'true';
}
function findStickerImagesInCard(wrapper) {
// Look for ANY stack in the card that contains sticker images
const stacks = wrapper.querySelectorAll('.mantine-Stack-root');
for (const stack of stacks) {
const imgs = stack.querySelectorAll('img[alt^="Sticker"]');
if (imgs.length > 0) return Array.from(imgs);
}
return [];
}
function adjustIconPositionForCard(wrapper) {
const icon = wrapper.querySelector('img[data-highlighter-icon="true"]');
if (!icon) return;
const stickers = findStickerImagesInCard(wrapper);
// Base padding on the right when no stickers
let offset = 8;
if (stickers.length > 0) {
const sample = stickers[0];
// Try to measure the actual width; fall back to 40px
const rect = sample.getBoundingClientRect();
const widthAttr = parseInt(sample.getAttribute('width'), 10);
const styleWidth = parseInt(sample.style.width, 10);
const stickerWidth =
(rect && rect.width) ||
(Number.isFinite(widthAttr) ? widthAttr : 0) ||
(Number.isFinite(styleWidth) ? styleWidth : 0) ||
40;
const gap = 8; // small spacing between sticker column and our icon
offset += Math.ceil(stickerWidth) + gap;
}
icon.style.right = offset + 'px';
}
function adjustAllIconPositions() {
const cards = document.querySelectorAll('.mantine-Card-root');
cards.forEach(adjustIconPositionForCard);
}
function scanAllImages() {
const images = document.querySelectorAll('img:not([data-dopplerFlagged])');
images.forEach(flagSkinImage);
// also keep icons positioned correctly if stickers appear later
adjustAllIconPositions();
}
scanAllImages();
// MutationObserver: rescan & readjust when DOM changes
const observer = new MutationObserver(() => {
scanAllImages();
adjustAllIconPositions();
});
observer.observe(document.body, { childList: true, subtree: true });
function handleLoad() {
setTimeout(() => {
scanAllImages();
adjustAllIconPositions();
}, 1000);
}
window.addEventListener('load', handleLoad);
})();