Skip to content

Instantly share code, notes, and snippets.

@nabbynz
Last active February 20, 2025 03:02
Show Gist options
  • Save nabbynz/51b83e03714d710fa6e3b18e97332198 to your computer and use it in GitHub Desktop.
Save nabbynz/51b83e03714d710fa6e3b18e97332198 to your computer and use it in GitHub Desktop.
Show Powerup Time Remaining
// ==UserScript==
// @name Show Powerup Time Remaining
// @description Shows the remaining active Powerup time. Plus a Tag count for the TagPro PUP.
// @version 0.5.0
// @match *://*.koalabeast.com/game
// @match *://*.koalabeast.com/game?*
// @updateURL https://gist.github.com/nabbynz/51b83e03714d710fa6e3b18e97332198/raw/Show_Powerup_Time_Remaining.user.js
// @downloadURL https://gist.github.com/nabbynz/51b83e03714d710fa6e3b18e97332198/raw/Show_Powerup_Time_Remaining.user.js
// @grant none
// @author nabby
// ==/UserScript==
console.log('START: ' + GM_info.script.name + ' (v' + GM_info.script.version + ' by ' + GM_info.script.author + ')');
'use strict';
/* eslint-env jquery */
/* globals tagpro, tagproConfig, PIXI */
/* eslint-disable no-multi-spaces */
let replayStarted = null;
tagpro.ready(() => {
let tr = tagpro.renderer;
if (tagproConfig.replay && tagpro.replayData && tagpro.replayData.packets[0][1] === 'recorder-metadata') {
replayStarted = tagpro.replayData.packets[0][2].started;
}
tr.updateJukeJuice = function(player) {
if (!player.sprites.jukeJuice) {
player.sprites.jukeJuice = tagpro.tiles.draw(player.sprites.ball, "jukeJuice", {x: 0, y: 23}, 17, 17);
}
if (!player.jukeJuice) {
player.sprites.jukeJuice.visible = false;
if (player.sprites.timerJJ) {
player.sprites.timerJJ.visible = false;
}
} else {
player.sprites.jukeJuice.visible = true;
addPUPTimer(player, 'jukeJuice', 'timerJJ', 'JJ:', '#00ffff');
}
};
tr.updateTagpro = function(player) {
if (!player.sprites.tagproTint) {
player.sprites.tagproTint = new PIXI.Graphics;
if (tagpro.events.fillTagproEffect) {
tagpro.events.fillTagproEffect[0].fillTagproEffect(player.sprites.tagproTint);
} else {
//player.sprites.tagproTint.beginFill(0x00FF00, 0.25).lineStyle(2, 0x00FF00).drawCircle(20, 20, 20); // default
player.sprites.tagproTint.lineStyle(2, 0x00FF20).beginFill(0x00FF20, 0.1).drawCircle(20, 20, 19); // color; lower fill opacity; 19px radius
}
player.sprites.tagproTint.alpha = 0.8; // lowers the opacity a bit
player.sprites.tagproTint.anchor = { x: 0.5, y: 0.5 };
player.sprites.ball.addChild(player.sprites.tagproTint);
}
if (!player.tagpro) {
player.sprites.tagproTint.visible = false;
if (player.sprites.timerTP) {
player.sprites.timerTP.visible = false;
}
} else {
player.sprites.tagproTint.visible = true;
addPUPTimer(player, 'tagpro', 'timerTP', 'TP:', '#00ff60');
}
if (!tr.options.disableParticles) {
if (player.tagpro && !player.sprites.tagproSparks) {
player.sprites.tagproSparks = tr.makeParticleEmitter(player.sprites.ball, [tr.particleFireTexture], tagpro.particleDefinitions.tagproSparks);
player.sprites.tagproSparks.player = player.id;
tr.emitters.push(player.sprites.tagproSparks);
} else if (!player.tagpro && player.sprites.tagproSparks) {
player.sprites.tagproSparks.emit = false;
tr.emitters.splice(tr.emitters.indexOf(player.sprites.tagproSparks), 1);
player.sprites.tagproSparks.destroy();
player.sprites.tagproSparks.cleanup();
player.sprites.tagproSparks = null;
}
}
};
const rollingBombStarPath = drawStarPath(0, 0, 4, 14, 4, 0);
tr.updateRollingBomb = function(player) {
if (!player.sprites.bomb) {
player.sprites.bomb = new PIXI.Graphics;
if (tagpro.events.fillRollingBombEffect) {
tagpro.events.fillRollingBombEffect[0].fillRollingBombEffect(player.sprites.bomb);
} else {
//player.sprites.bomb.beginFill(0xFFFF00, 0.75).drawCircle(20, 20, 19); // default
player.sprites.bomb.lineStyle(2, 0xffff00, 1).drawCircle(0, 0, 14).lineStyle(1, 0xffff00, 0.8).drawCircle(0, 0, 17).beginFill(0xff8800, 1).lineStyle(1, 0x000000, 0.6).drawPolygon(rollingBombStarPath); // orange star
}
player.sprites.bomb.position.set(20, 20);
player.sprites.ball.addChild(player.sprites.bomb);
}
if (player.bomb) {
player.sprites.bomb.visible = true;
addPUPTimer(player, 'bomb', 'timerRB', 'TP:', '#eeaa00');
} else {
player.sprites.bomb.visible = false;
if (player.sprites.timerRB) {
player.sprites.timerRB.visible = false;
}
}
if (!tr.options.disableParticles) {
if (player.bomb && !player.sprites.rollingBomb) {
player.sprites.rollingBomb = tr.makeParticleEmitter(player.sprites.ball, [tr.particleTexture], tagpro.particleDefinitions.rollingBomb);
tr.emitters.push(player.sprites.rollingBomb);
} else if (!player.bomb && player.sprites.rollingBomb) {
player.sprites.rollingBomb.emit = false;
tr.emitters.splice(tr.emitters.indexOf(player.sprites.rollingBomb), 1);
player.sprites.rollingBomb.destroy();
player.sprites.rollingBomb = null;
}
}
};
tr.updateRollingBombAlpha = function(player) {
if (player.bomb && player.sprites.bomb) {
player.sprites.bomb.alpha = Math.abs(1.0 * Math.sin(performance.now() / 80)); // brighter and faster flashing
}
};
});
let pupTimerText = function (text, color) {
return new PIXI.Text(text, {
fontFamily: 'Arial',
fontSize: '11px',
fontWeight: 'bold',
fill: color || '#FFFFFF',
stroke: '#000000',
strokeThickness: 2,
lineJoin: 'round',
dropShadow: true,
dropShadowColor: '#000000',
dropShadowAngle: 0,
dropShadowDistance: 0,
dropShadowBlur: 2,
dropShadowAlpha: 0.8,
});
};
let updatePUPTimers = function(player) {
if ((player.jukeJuice || player.tagpro || player.bomb) && tagpro.state !== 2) { // && now - player.sprites?.timersLastUpdate >= 100 * tagpro.replaySpeed
let now = replayStarted ? replayStarted + tagpro.replayPlayer.player.currentTime * tagpro.replaySpeed : Date.now();
let posY = 6;
if (player.jukeJuice && player.sprites && player.sprites.timerJJ) {
if (tagpro.state === 5 && player.jukeJuice > 1 && player.flag && !player.prevFlag) { // player had a JJ, then grabbed flag in OT so reset timer now (server doesn't send update until current JJ expires?)
player.sprites.timerJJ.takenAt = now - 20; // allow an extra ~tick
}
const secondsLeft = 20 - (now - player.sprites.timerJJ.takenAt) / 1000;
player.sprites.timerJJ.text = secondsLeft >= 0 && secondsLeft <= 20 ? 'JJ:' + secondsLeft.toFixed(1) : '';
player.sprites.timerJJ.x = player.sprites.name.x + 14;
player.sprites.timerJJ.y = posY;
posY += 11;
player.prevFlag = player.flag;
}
if (player.tagpro && player.sprites && player.sprites.timerTP) {
const secondsLeft = 20 - (now - player.sprites.timerTP.takenAt) / 1000;
player.sprites.timerTP.text = secondsLeft >= 0 && secondsLeft <= 20 ? 'TP:' + secondsLeft.toFixed(1) + ' [' + (player['s-tags'] - player.sprites.timerTP.tagCount) + ']' : ''; // this will include gate kills
player.sprites.timerTP.x = player.sprites.name.x + 14;
player.sprites.timerTP.y = posY;
posY += 11;
}
if (player.bomb && player.sprites && player.sprites.timerRB) {
const secondsLeft = 20 - (now - player.sprites.timerRB.takenAt) / 1000;
player.sprites.timerRB.text = secondsLeft >= 0 && secondsLeft <= 20 ? 'RB:' + secondsLeft.toFixed(1) : '';
player.sprites.timerRB.x = player.sprites.name.x + 14;
player.sprites.timerRB.y = posY;
}
player.rafId = requestAnimationFrame(() => {
updatePUPTimers(player);
});
}
};
let addPUPTimer = function(player, pupType, timerType, prefix, color = '#dddddd') {
const takenAt = replayStarted ? player[pupType] > 1 ? player[pupType] + 20000 : replayStarted + tagpro.replayPlayer.player.currentTime * tagpro.replaySpeed : Date.now();
if (!player.sprites[timerType]) {
player.sprites[timerType] = pupTimerText(prefix + '20.0', color);
player.sprites[timerType].x = player.sprites.name.x + 14;
player.sprites[timerType].y = 6;
player.sprites.info.addChild(player.sprites[timerType]);
player.sprites[timerType].visible = false;
}
if (tagpro.state === 5 && player.jukeJuice === true && player.sprites.timerJJ.visible && pupType === 'jukeJuice') { // don't reset timer if OT grab with JJ (handled in updatePUPTimers)
return;
}
player.sprites[timerType].takenAt = takenAt;
player.sprites[timerType].visible = true;
player.sprites[timerType].tagCount = player['s-tags']; // only for tagpro
if (player.rafId) {
cancelAnimationFrame(player.rafId);
}
updatePUPTimers(player);
};
function drawStarPath(x, y, points, radius, innerRadius, rotation) {
if (rotation === void 0) { rotation = 0; }
innerRadius = innerRadius || radius / 2;
var startAngle = (-1 * Math.PI / 2) + rotation;
var len = points * 2;
var delta = (Math.PI * 2) / len;
var polygon = [];
for (var i = 0; i < len; i++) {
var r = i % 2 ? innerRadius : radius;
var angle = (i * delta) + startAngle;
polygon.push(x + (r * Math.cos(angle)), y + (r * Math.sin(angle)));
}
return polygon;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment