// ==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);
}
});
})();