Skip to content

Instantly share code, notes, and snippets.

@nabbynz
Last active February 20, 2025 02:47
Show Gist options
  • Save nabbynz/61cdab937d61bb2f6eb4ce43ca363a1c to your computer and use it in GitHub Desktop.
Save nabbynz/61cdab937d61bb2f6eb4ce43ca363a1c to your computer and use it in GitHub Desktop.
TagPro Ball Shadow & Shine
// ==UserScript==
// @name TagPro Ball Shadow & Shine
// @description Adds a Shadow and Shine to Balls
// @version 0.0.1
// @include *.koalabeast.com/game
// @include *.koalabeast.com/game?*
// @updateURL https://gist.github.com/nabbynz/61cdab937d61bb2f6eb4ce43ca363a1c/TagPro_Ball_Shadow_&_Shine.user.js
// @downloadURL https://gist.github.com/nabbynz/61cdab937d61bb2f6eb4ce43ca363a1c/TagPro_Ball_Shadow_&_Shine.user.js
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @grant none
// @author nabby
// ==/UserScript==
'use strict';
console.log('START: ' + GM_info.script.name + ' (v' + GM_info.script.version + ' by ' + GM_info.script.author + ')');
/* eslint-env jquery */
/* globals tagpro, tagproConfig, PIXI */
/* eslint-disable no-multi-spaces */
/* eslint-disable dot-notation */
const canvas_size = 64;
const canvas_center = canvas_size / 2;
let createShadowAndShine = function() {
let shadowShineCanvas = createCanvas(canvas_size, canvas_size);
let shadowShineCtx = shadowShineCanvas.getContext('2d');
// create shadow...
shadowShineCtx.fillStyle = '#000000';
shadowShineCtx.globalCompositeOperation = 'source-over';
shadowShineCtx.globalAlpha = 0.8;
shadowShineCtx.filter = 'blur(4px)';
shadowShineCtx.beginPath();
shadowShineCtx.ellipse(canvas_center, canvas_center + 16, 16, 7, 0, 0, Math.PI * 2);
shadowShineCtx.fill();
shadowShineCtx.globalAlpha = 0.65;
shadowShineCtx.filter = 'blur(2px)';
shadowShineCtx.beginPath();
shadowShineCtx.ellipse(canvas_center, canvas_center + 17, 10, 5, 0, 0, Math.PI * 2);
shadowShineCtx.fill();
shadowShineCtx.globalCompositeOperation = 'destination-out';
shadowShineCtx.globalAlpha = 1;
shadowShineCtx.filter = 'blur(1px)';
shadowShineCtx.beginPath();
shadowShineCtx.arc(canvas_center, canvas_center, 18.5, 0, Math.PI * 2);
shadowShineCtx.fill();
// create shine...
shadowShineCtx.fillStyle = '#ffffff';
shadowShineCtx.globalCompositeOperation = 'source-over';
shadowShineCtx.globalAlpha = 0.8;
shadowShineCtx.filter = 'blur(3px)';
shadowShineCtx.beginPath();
shadowShineCtx.ellipse(canvas_center + 8, canvas_center - 10, 9, 4, Math.PI / 4, 0, Math.PI * 2);
shadowShineCtx.fill();
shadowShineCtx.globalAlpha = 0.6;
shadowShineCtx.filter = 'blur(2px)';
shadowShineCtx.beginPath();
shadowShineCtx.arc(canvas_center + 8, canvas_center - 10, 5, 0, Math.PI * 2);
shadowShineCtx.fill();
shadowShineCtx.globalAlpha = 0.85;
shadowShineCtx.filter = 'blur(1px)';
shadowShineCtx.beginPath();
shadowShineCtx.arc(canvas_center + 9, canvas_center - 11, 3, 0, Math.PI * 2);
shadowShineCtx.fill();
// remove the little bit of shine that was drawn outside the ball...
shadowShineCtx.globalCompositeOperation = 'destination-in';
shadowShineCtx.globalAlpha = 1;
shadowShineCtx.filter = 'blur(1px)';
shadowShineCtx.beginPath();
shadowShineCtx.arc(canvas_center, canvas_center, 19, 0, Math.PI * 2);
shadowShineCtx.arc(canvas_center, canvas_center + 19, 19, 0, Math.PI * 2);
shadowShineCtx.fill();
let shadowShineTexture = PIXI.Texture.from(shadowShineCanvas);
PIXI.Texture.addToCache(shadowShineTexture, 'BallShadowShineTexture');
};
let addBallSkin = function(player) {
player.sprites.shadowshine = new PIXI.Sprite(PIXI.utils.TextureCache.BallShadowShineTexture);
player.sprites.shadowshine.position.set(20, 20);
player.sprites.shadowshine.pivot.set(canvas_center, canvas_center);
player.sprites.ball.addChild(player.sprites.shadowshine);
};
let modifyTagProFunctions = function() {
let old_createBallSprite = tagpro.renderer.createBallSprite;
// add to new players...
tagpro.renderer.createBallSprite = function(player) {
old_createBallSprite(player);
addBallSkin(player);
};
// add to existing players...
for (let playerId in tagpro.players) {
if (tagpro.players[playerId] && !tagpro.players[playerId].sprites.shadowshine) {
addBallSkin(tagpro.players[playerId]);
}
}
};
let isEvent = false;
let isHalloween = false;
let isBirthday = false;
let isEaster = false;
let isEgg = false;
let isHockey = false;
let isChristmas = false;
let isAprilFools = false;
let isEggEvent;
let checkForEvent = function() {
let scriptSrcs = [];
if (tagproConfig.replay) {
let packets = tagpro.replayData.packets;
if (!Array.isArray(packets)) {
packets = packets.split('\n');
}
for (let i = 0; i < packets.length; i++) {
const packet = Array.isArray(packets[i]) ? packets[i] : JSON.parse(packets[i]);
if (packet[1] === 'clientInfo' && packet[2].hasOwnProperty('eventScripts') && packet[2].eventScripts.length) {
scriptSrcs = packet[2].eventScripts;
console.log(GM_info.script.name, 'scriptSrcs:', scriptSrcs);
break;
}
}
}
let scripts = $('script[src]').toArray();
scripts.forEach(script => {
scriptSrcs.push(script.src);
})
if (scriptSrcs) {
let scriptNames = ['halloween', 'birthday', 'easter', 'egg', 'hockey', 'pirates', 'christmas']; // disable for Halloween, Birthday, Easter/Eggball/Hockey & Pirates events
for (let scriptName of scriptNames) {
if (scriptSrcs.some(e => e.includes(scriptName))) { //eg: https://static.koalabeast.com/events/easter-2017.js
isEvent = true;
if (scriptName === 'halloween') isHalloween = true;
if (scriptName === 'birthday' || scriptName === 'pirates') isBirthday = true;
if (scriptName === 'easter') isEaster = true;
if (scriptName === 'egg') isEgg = true;
if (scriptName === 'hockey') isHockey = true;
if (scriptName === 'christmas') isChristmas = true;
break;
}
}
}
isEggEvent = isEaster || isEgg || isHockey;
isAprilFools = !!document.querySelector('#redspecial'); // to detect the April Fools Event triangle & square ball shapes
console.log(GM_info.script.name + ':: checkForEvent() isEvent:'+isEvent, 'isHalloween:'+isHalloween, 'isBirthday:'+isBirthday, 'isEaster:'+isEaster, 'isEgg:'+isEgg, 'isHockey:'+isHockey, 'isChristmas:'+isChristmas, 'isAprilFools:'+isAprilFools, 'isEggEvent:'+isEggEvent);
};
tagpro.ready(function() {
checkForEvent();
if (isEvent) { // don't start if there's an event running
return;
}
createShadowAndShine();
let readyToDraw = function() {
return document.visibilityState === 'visible' && tagpro.tiles && tagpro.tiles.image && tagpro.playerId;
};
let start = function() {
if (!readyToDraw()) {
setTimeout(start, 50);
return false;
} else {
document.removeEventListener('visibilitychange', start);
setTimeout(() => {
modifyTagProFunctions();
}, 200);
}
};
if (document.visibilityState === 'hidden') {
document.addEventListener('visibilitychange', start);
} else {
start();
}
});
function createCanvas(width, height, forceDOM = false) {
if (!forceDOM && typeof OffscreenCanvas !== 'undefined') {
return new OffscreenCanvas(width, height); // An 'OffscreenCanvas' is smaller and faster than a normal canvas.
} else {
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment