Greasy Fork is available in English.

It's Raining Mortogs

It's always raining Mortogs

// ==UserScript==
// @name         It's Raining Mortogs
// @version      2025.01.08
// @description  It's always raining Mortogs
// @match        *://*.neopets.com/*
// @icon         https://images.neopets.com/new_shopkeepers/t_1900.gif
// @author       Posterboy
// @namespace    https://greasyfork.org/users/1277376
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const config = {
        fallingSpeed: 0.3, // Falling speed in seconds 0.3 is approximately what Neopets uses
        maxVisibleMortogs: 50, // Throttle limit of mortogs on screen at a time
        mortogsPerSecond: 50, // Mortogs to create per second

//images can be replaced with just standard neopets.com green mortogs if so desired

        mortogImages: [
            'https://i.imgur.com/CLxfgmq.png',
            'https://i.imgur.com/jbAzG1I.png',
            'https://i.imgur.com/TtBjq01.png',
            'https://i.imgur.com/VllQVFg.png',
            'https://i.imgur.com/DgNMTdR.png',
            'https://i.imgur.com/FvNreXu.png',
            'https://i.imgur.com/9MiYGQY.png',
            'https://i.imgur.com/M6KS8tS.png',
            'https://i.imgur.com/rUo8osf.png',
            'https://i.imgur.com/BhtUf2V.png',
            'https://i.imgur.com/ykkxh2o.png',
            'https://i.imgur.com/ji1aZPq.png'
        ]
    };

    // Preload images
    const mortogImages = config.mortogImages.map(src => {
        const img = new Image();
        img.src = src;
        return img;
    });

    const mortogContainer = document.createElement('div');
    Object.assign(mortogContainer.style, {
        position: 'fixed',
        top: '0',
        left: '0',
        width: '100%',
        pointerEvents: 'none',
        zIndex: '9999'
    });
    document.body.appendChild(mortogContainer);

    let currentMortogs = 0;

    function getRandomMortogImage() {
        const randomIndex = Math.floor(Math.random() * mortogImages.length);
        return mortogImages[randomIndex].src;
    }

    function createFallingMortog() {
        if (currentMortogs >= config.maxVisibleMortogs) return;

        const img = document.createElement('img');
        img.src = getRandomMortogImage();
        img.classList.add('falling-mortog');
        Object.assign(img.style, {
            position: 'absolute',
            top: '-100px',
            width: '100px',
            height: 'auto'
        });

        const viewportWidth = window.innerWidth;
        const leftOffset = (viewportWidth - viewportWidth * 0.9) / 2;
        const randomLeft = Math.floor(Math.random() * (viewportWidth * 0.9 - 100)) + leftOffset;
        img.style.left = `${randomLeft}px`;

        mortogContainer.appendChild(img);
        currentMortogs++;

        let startTime;
        function animate(time) {
            if (!startTime) startTime = time;
            const elapsed = time - startTime;
            const topPosition = Math.min((elapsed / (config.fallingSpeed * 1000)) * window.innerHeight, window.innerHeight);
            img.style.top = `${topPosition}px`;

            if (topPosition < window.innerHeight) {
                requestAnimationFrame(animate);
            } else {
                img.style.transition = 'opacity 0.5s';
                img.style.opacity = '0';
                setTimeout(() => {
                    img.remove();
                    currentMortogs--;
                }, 500);
            }
        }

        requestAnimationFrame(animate);
    }

    const interval = 1000 / config.mortogsPerSecond;
    let totalMortogs = config.mortogsPerSecond * config.duration;
    const intervalId = setInterval(() => {
        if (totalMortogs <= 0) {
            clearInterval(intervalId);
            return;
        }
        createFallingMortog();
        totalMortogs--;
    }, interval);
})();