Niro's GS Speedrun Timer

Adds a MM:SS:msmsms timer to the top right of the screen with start, stop, and reset controls

// ==UserScript==
// @name         Niro's GS Speedrun Timer
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Adds a MM:SS:msmsms timer to the top right of the screen with start, stop, and reset controls
// @author       Niro ("nirokr" on Discord or @NiroGS on YouTube)
// @match        *://*/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // List of allowed websites
    const allowedWebsites = [
        "https://nirogs.github.io/GetawayShootout/",
        "https://htmlxm.github.io/h4/getaway-shootout/",
        "https://ubg44.github.io/GetawayShootout/",
        "https://watchdocumentaries.com/getaway-shootout-game/",
        "https://ducklife4.github.io/play/getaway-shootout.html",
        "https://sites.google.com/site/thegamecompilation/getaway-shootout",
        "https://play.unity.com/en/games/f5c4d162-bae9-48ee-8238-1b7f039503ed/getaway-shootout",
        "https://www.twoplayergames.org/game/getaway-shootout",
        "https://tbg95.github.io/getaway-shootout/",
        "https://pizzaedition.one/g/getawayshootout/",
        "https://sites.google.com/view/iogames/getaway-shootout-io",
        "https://lablockedgames.com/getaway-shootout",
        "https://www.sites.google.com/site/unblockedgamestop/getaway-shootout",
        "https://coolunblockedgame.com/game/getaway-shootout/",
        "https://getawayshootout.io/",
        "https://eggy-car.github.io/detail/getaway-shootout.html",
        "https://nirogs.github.io/NewGetawayShootout/",
        "https://games.crazygames.com/en_US/getaway-shootout/index.html",
        "https://www.crazygames.com/game/getaway-shootout",
        "https://poki.com/en/g/getaway-shootout"
    ];

    if (!allowedWebsites.some(site => window.location.href.startsWith(site.replace("*", "")))) {
        return;
    }

    let getawayStages = [];
    let numGetaways = parseInt(prompt("How many getaways? (3, 4, or 5)", "3"));
    if (numGetaways === 3) {
        getawayStages = ["Market", "Bus", "Train"];
    } else if (numGetaways === 4) {
        getawayStages = ["Plane", "Market", "Bus", "Train"];
    } else if (numGetaways === 5) {
        getawayStages = ["Train", "Office", "Market", "Bus", "Train"];
    } else {
        alert("Invalid input! Defaulting to 3 getaways.");
        getawayStages = ["Market", "Bus", "Train"];
    }

    let timerDiv = document.createElement('div');
    timerDiv.style.position = 'fixed';
    timerDiv.style.top = '15%';
    timerDiv.style.right = '10px';
    timerDiv.style.background = 'rgba(0, 0, 0, 0.7)';
    timerDiv.style.color = 'white';
    timerDiv.style.padding = '5px 10px';
    timerDiv.style.fontSize = '18px';
    timerDiv.style.fontFamily = 'monospace';
    timerDiv.style.borderRadius = '2px';
    timerDiv.style.zIndex = '99999';
    timerDiv.innerText = '00:00:000';
    document.body.appendChild(timerDiv);

    let splitsDiv = document.createElement('div');
    splitsDiv.style.position = 'fixed';
    splitsDiv.style.top = 'calc(15% + 30px)';
    splitsDiv.style.right = '10px';
    splitsDiv.style.background = 'rgba(0, 0, 0, 0.7)';
    splitsDiv.style.color = 'white';
    splitsDiv.style.padding = '5px 10px';
    splitsDiv.style.fontSize = '14px';
    splitsDiv.style.fontFamily = 'monospace';
    splitsDiv.style.borderRadius = '2px';
    splitsDiv.style.zIndex = '99999';
    splitsDiv.style.textAlign = 'right';
    document.body.appendChild(splitsDiv);

    let startTime = 0;
    let elapsedTime = 0;
    let running = false;
    let finished = false;
    let animationFrame;
    let splits = Array(getawayStages.length).fill("--:--:---");
    let lastSplitTime = 0;

    function updateTimer() {
        let now = performance.now() - startTime + elapsedTime;
        let minutes = Math.floor(now / 60000).toString().padStart(2, '0');
        let seconds = Math.floor((now % 60000) / 1000).toString().padStart(2, '0');
        let milliseconds = Math.floor(now % 1000).toString().padStart(3, '0');
        timerDiv.innerText = `${minutes}:${seconds}:${milliseconds}`;
        if (running) {
            animationFrame = requestAnimationFrame(updateTimer);
        }
    }

    function updateSplits() {
        splitsDiv.innerHTML = splits.map((split, index) => `<div>${getawayStages[index] || 'Split ' + (index + 1)}: ${split}</div>`).join('');
    }
    updateSplits();

    document.addEventListener('keydown', (event) => {
        if (event.key === '1' && !event.repeat && !finished) {
            if (!running) {
                startTime = performance.now();
                running = true;
                updateTimer();
                // First press only starts the timer – no split recorded
                return;
            }
            let now = performance.now() - startTime + elapsedTime;
            let minutes = Math.floor(now / 60000).toString().padStart(2, '0');
            let seconds = Math.floor((now % 60000) / 1000).toString().padStart(2, '0');
            let milliseconds = Math.floor(now % 1000).toString().padStart(3, '0');

            let splitIndex = splits.findIndex(time => time === "--:--:---");
            if (splitIndex !== -1 && splitIndex < getawayStages.length && running) {
                splits[splitIndex] = `${minutes}:${seconds}:${milliseconds}`;
                updateSplits();

                if (splitIndex === getawayStages.length - 1) {
                    elapsedTime += performance.now() - startTime;
                    running = false;
                    finished = true;
                    cancelAnimationFrame(animationFrame);

                    let finalTime = elapsedTime + 2500;
                    let finalMinutes = Math.floor(finalTime / 60000).toString().padStart(2, '0');
                    let finalSeconds = Math.floor((finalTime % 60000) / 1000).toString().padStart(2, '0');
                    let finalMilliseconds = Math.floor(finalTime % 1000).toString().padStart(3, '0');
                    timerDiv.innerText = `${finalMinutes}:${finalSeconds}:${finalMilliseconds}`;
                }
            }
        } else if (event.key === '2' && running) {
            elapsedTime += performance.now() - startTime;
            running = false;
            cancelAnimationFrame(animationFrame);
        } else if (event.key === '0') {
            running = false;
            finished = false;
            elapsedTime = 0;
            splits = Array(getawayStages.length).fill("--:--:---");
            timerDiv.innerText = '00:00:000';
            updateSplits();
            cancelAnimationFrame(animationFrame);
        }
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址