Nitro Type - Loadout Randomizer

Randomizes your selected items

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Nitro Type - Loadout Randomizer
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Randomizes your selected items
// @author       thisisks
// @match        https://www.nitrotype.com/race*
// @match        https://www.nitrotype.com/garage/customizer*
// @run-at       document-start
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const isRace = location.pathname.startsWith("/race");
    const isCustomizer = location.pathname.startsWith("/garage/customizer");

    // -----------------------------
    // CORE RANDOMIZER (shared)
    // -----------------------------
    async function runRandomizer() {
        const random = (arr) => arr[Math.floor(Math.random() * arr.length)];

        const raw = localStorage.getItem("persist:nt");
        if (!raw) return console.error("persist:nt not found");

        const parsed = JSON.parse(raw);

        let dataKey = null;
        let data = null;

        for (const key in parsed) {
            try {
                const obj = JSON.parse(parsed[key]);
                if (obj && obj.cars && obj.loot) {
                    data = obj;
                    dataKey = key;
                    break;
                }
            } catch {}
        }

        if (!data) return console.error("Player data not found");

        const cars = data.cars.map(c => ({
            id: c[0],
            hueAngle: c[2] || 0
        }));

        const trails = data.loot.filter(l => l.type === "trail");
        const nitros = data.loot.filter(l => l.type === "nitro");
        const nametags = data.loot.filter(l => l.type === "nametag");
        const titles = data.loot.filter(l => l.type === "title");

        const car = random(cars);
        const trail = random(trails);
        const nitro = random(nitros);
        const nametag = random(nametags);
        const title = random(titles);
        const perk = Math.random() < 0.5 ? 1 : 0;

        data.carID = car.id;
        data.carHueAngle = car.hueAngle;
        data.title = title.name;
        data.disablePerk = perk;

        const typesToHandle = ["trail", "nitro", "nametag"];

        data.loot.forEach(item => {
            if (typesToHandle.includes(item.type)) {
                item.equipped = 0;
            }
        });

        data.loot.forEach(item => {
            if (item.type === "trail" && item.lootID === trail.lootID) item.equipped = 1;
            if (item.type === "nitro" && item.lootID === nitro.lootID) item.equipped = 1;
            if (item.type === "nametag" && item.lootID === nametag.lootID) item.equipped = 1;
        });

        parsed[dataKey] = JSON.stringify(data);
        localStorage.setItem("persist:nt", JSON.stringify(parsed));

        const payload = [
            { id: car.id, hueAngle: car.hueAngle, type: "car" },
            { id: trail.lootID, type: "trail" },
            { id: nitro.lootID, type: "nitro" },
            { id: nametag.lootID, type: "nametag" },
            { id: title.lootID, type: "title" },
            { disablePerk: perk, type: "perk" }
        ];

        const token = localStorage.getItem("player_token");

        await fetch("https://www.nitrotype.com/api/v2/loot/equip", {
            method: "POST",
            headers: {
                authorization: `Bearer ${token}`,
                "content-type": "application/json"
            },
            body: JSON.stringify(payload),
            credentials: "include"
        });

        console.log("Randomized & saved");
    }

    // -----------------------------
    // FIX: race-safe execution (wait for data)
    // -----------------------------
    function runOnRaceWhenReady() {
        let tries = 0;

        const interval = setInterval(() => {
            tries++;

            const raw = localStorage.getItem("persist:nt");
            if (raw) {
                clearInterval(interval);
                runRandomizer();
                return;
            }

            // stop after ~10s to avoid infinite loop
            if (tries > 50) {
                clearInterval(interval);
                console.error("Timed out waiting for persist:nt");
            }
        }, 200);
    }

    // -----------------------------
    // CUSTOMIZER BUTTON
    // -----------------------------
    function injectButton() {
        const nav = document.querySelector(".customizer--tabs.nav-list");
        if (!nav || document.querySelector("#nt-randomizer-btn")) return;

        const btn = document.createElement("div");
        btn.id = "nt-randomizer-btn";
        btn.className = "nav-list-item customizer--tab";
        btn.innerHTML = `
            <div class="customizer--tab--content">
                <div class="customizer--tab--icon">🎲</div>
                <div class="customizer--tab--label">Randomize</div>
            </div>
        `;

        btn.style.cursor = "pointer";

        btn.addEventListener("click", async () => {
            btn.style.opacity = "0.6";
            btn.style.pointerEvents = "none";

            await runRandomizer();
            location.reload();
        });

        nav.appendChild(btn);
    }

    // -----------------------------
    // ROUTER
    // -----------------------------
    if (isRace) {
        runOnRaceWhenReady();
    }

    if (isCustomizer) {
        const obs = new MutationObserver(injectButton);
        obs.observe(document.documentElement, { childList: true, subtree: true });
        injectButton();
    }

})();