Skip to content

Instantly share code, notes, and snippets.

@Kitue
Last active December 23, 2024 15:50
Show Gist options
  • Save Kitue/2431baa6df27d782dc0d6c9ca503331f to your computer and use it in GitHub Desktop.
Save Kitue/2431baa6df27d782dc0d6c9ca503331f to your computer and use it in GitHub Desktop.
Counts daily total battles, daily battles per opponent and obelisk skirmish battles.
// ==UserScript==
// @name Neopets Battle Counter
// @version 1.4
// @description Counts your total daily battles, battles per day per opponent (displayed on relevant opponent page only) and tracks your total Obelisk battles per skirmish.
// @author Raven
// @match *://www.neopets.com/dome/arena.phtml
// @grant none
// ==/UserScript==
(function () {
'use strict';
// CONFIGURABLE SETTINGS // Change between true/false to edit how counts are displayed
const showTotalBattleCount = true; // Display a daily count of all your battles (resets daily)
const showObeliskBattleCount = true; // Display a count of your total skirmish battles (resets at start of new skirmish)
const showOpponentBattleCount = true; // Display a daily count for battles vs the active opponent (resets daily)
const recordWinsOnly = false; // Set to true to record only wins, set to false to record all battles including draws and losses
const OnlyOnObeliskPage = true; // Show Obelisk counter only when battling Obelisk opponents
// END CONFIGURABLE SETTINGS //
let battleCounted = false;
const BattleRecordAge = 7; // In days
// Create a counter container in the middle of the popup
function createCounterContainer() {
const popupContents = document.querySelector('.bdPopupGeneric.middle');
if (!popupContents) return null;
let counterContainer = document.getElementById('battleCounterContainer');
if (!counterContainer) {
counterContainer = document.createElement('div');
counterContainer.id = 'battleCounterContainer';
counterContainer.style.position = 'absolute';
counterContainer.style.bottom = '10px';
counterContainer.style.width = '98%';
counterContainer.style.margin = '5px';
counterContainer.style.borderRadius = '4px';
counterContainer.style.backgroundColor = '#FFFFFF';
counterContainer.style.zIndex = '1000';
counterContainer.style.textAlign = 'center';
counterContainer.style.display = 'flex';
counterContainer.style.flexDirection = 'column';
counterContainer.style.gap = '0px';
popupContents.appendChild(counterContainer);
}
return counterContainer;
}
function createCombinedCounter() {
const counterContainer = createCounterContainer();
if (!counterContainer) return;
let combinedCounter = document.getElementById('combinedBattleCounter');
if (!combinedCounter) {
combinedCounter = document.createElement('div');
combinedCounter.id = 'combinedBattleCounter';
combinedCounter.style.padding = '2px';
combinedCounter.style.width = '90%';
combinedCounter.style.margin = '0 auto';
combinedCounter.style.display = 'block';
counterContainer.appendChild(combinedCounter);
}
updateCombinedCounter();
}
// Update the combined counter to display battle counts
function updateCombinedCounter() {
const totalCount = showTotalBattleCount ? (localStorage.getItem('totalBattleCount') || '0') : null;
const obeliskCount = showObeliskBattleCount ? (localStorage.getItem('obeliskBattleCount') || '0') : null;
const combinedCounter = document.getElementById('combinedBattleCounter');
if (combinedCounter) {
let displayText = '';
if (totalCount !== null) {
displayText += `Total Daily ${recordWinsOnly ? 'Wins' : 'Battles'}: <span style="color: #C41E3A;">${parseInt(totalCount).toLocaleString()}</span>`;
}
if (obeliskCount !== null && parseInt(obeliskCount) > 0 && (!OnlyOnObeliskPage || isObeliskOpponent())) {
if (displayText) displayText += ' | ';
displayText += `Skirmish ${recordWinsOnly ? 'Wins' : 'Battles'}: <span style="color: #C41E3A;">${parseInt(obeliskCount).toLocaleString()}</span>`;
}
if (displayText) {
combinedCounter.innerHTML = `<strong>${displayText}</strong>`;
combinedCounter.style.display = 'block';
} else {
combinedCounter.style.display = 'none';
}
}
}
// Add obelisk contribution (for debugging)
function addObeliskContribution() {
const div = document.createElement('div'); // Declare the `div` variable
div.textContent = "Obelisk Contribution Added";
document.body.appendChild(div); // Append the div to the document body
return "Obelisk contribution added successfully!";
}
window.addObeliskContribution = addObeliskContribution;
// Initialize opponent-specific counters
function initializeOpponentCounter(opponentName) {
const counterId = `battleCount-${opponentName}`;
const label = `Daily ${recordWinsOnly ? 'Wins' : 'Battles'} VS ${opponentName}`;
const container = createCounterContainer();
if (!document.getElementById(counterId)) {
const opponentCounter = document.createElement('div');
opponentCounter.id = counterId;
opponentCounter.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
opponentCounter.style.padding = '4px';
opponentCounter.style.borderRadius = '4px';
opponentCounter.style.width = '90%';
opponentCounter.style.margin = '0 auto';
opponentCounter.innerHTML = `<strong>${label}: <span id="${counterId}-value" style="color: #C41E3A;">0</span></strong>`;
container.appendChild(opponentCounter);
}
resetCounterIfNecessary(counterId);
const storedValue = localStorage.getItem(counterId) || '0';
updateCounter(counterId, storedValue);
}
// Reset counter if necessary (e.g., daily reset)
function resetCounterIfNecessary(counterKey, resetDays = 1) {
const currentDate = new Date();
const pstDate = new Date(currentDate.toLocaleString('en-US', { timeZone: 'America/Los_Angeles' }));
const midnightPST = new Date(pstDate.setHours(0, 0, 0, 0));
const storedDate = localStorage.getItem(`${counterKey}-date`);
const lastDate = storedDate ? new Date(storedDate) : null;
const storedTimestamp = localStorage.getItem(`${counterKey}-timestamp`);
const lastTimestamp = storedTimestamp ? new Date(storedTimestamp) : null;
const sevenDaysAgo = new Date(currentDate - BattleRecordAge * 24 * 60 * 60 * 1000);
if (lastTimestamp && lastTimestamp < sevenDaysAgo) {
localStorage.removeItem(counterKey); // Remove the old records
localStorage.removeItem(`${counterKey}-timestamp`);
localStorage.removeItem(`${counterKey}-date`);
}
if (counterKey === 'obeliskBattleCount') {
const isMonday = pstDate.getDay() === 1; // 0 = Sunday, 1 = Monday
if (!lastDate || (isMonday && pstDate >= midnightPST && pstDate.getDate() !== lastDate.getDate())) {
localStorage.setItem(`${counterKey}-date`, midnightPST.toISOString());
localStorage.setItem(counterKey, '0');
}
} else {
if (!lastDate || pstDate >= midnightPST && pstDate.getDate() !== lastDate.getDate()) {
localStorage.setItem(`${counterKey}-date`, midnightPST.toISOString());
localStorage.setItem(counterKey, '0');
}
}
}
// Check if current opponent is from the Obelisk section
function isObeliskOpponent() {
const p2headshot = document.querySelector('#p2headshot');
if (p2headshot) {
const backgroundImage = p2headshot.style.backgroundImage || '';
const obeliskFactions = ['_order', '_thief', '_awakened', '_seekers', '_brute', '_sway'];
return obeliskFactions.some((faction) => backgroundImage.includes(faction));
}
return false;
}
// Increment the counter based on the key
function incrementCounter(counterKey, opponent, resetDays = 1) {
resetCounterIfNecessary(counterKey, resetDays);
const currentCount = parseInt(localStorage.getItem(counterKey) || '0', 10) + 1;
localStorage.setItem(counterKey, currentCount);
localStorage.setItem(`${counterKey}-timestamp`, new Date().toISOString());
if (opponent) {
const opponentKey = `battleCount-${opponent}`;
resetCounterIfNecessary(opponentKey, resetDays);
const opponentCount = parseInt(localStorage.getItem(opponentKey) || '0', 10) + 1;
localStorage.setItem(opponentKey, opponentCount);
localStorage.setItem(`${opponentKey}-timestamp`, new Date().toISOString());
return opponentCount;
}
return currentCount;
}
// Update the counter displayed on the page
function updateCounter(counterId, value) {
const counterElement = document.getElementById(`${counterId}-value`);
if (counterElement) {
counterElement.textContent = parseInt(value).toLocaleString();
}
}
// Clean up expired records
function cleanupExpiredRecords() {
const now = new Date();
const sevenDaysAgo = new Date(now - BattleRecordAge * 24 * 60 * 60 * 1000);
Object.keys(localStorage).forEach((key) => {
if (key.endsWith('-timestamp')) {
const timestamp = new Date(localStorage.getItem(key));
if (timestamp < sevenDaysAgo) {
const baseKey = key.replace('-timestamp', '');
localStorage.removeItem(baseKey);
localStorage.removeItem(key);
localStorage.removeItem(`${baseKey}-date`);
}
}
});
}
// Initialize all counters
function initializeCounters() {
createCombinedCounter();
const opponent = getOpponentName();
if (showOpponentBattleCount && opponent !== 'Unknown Opponent') {
initializeOpponentCounter(opponent);
}
if (!checkInitialHP()) {
return; // Do not initialize counters if either starts with 0 HP
}
const hpCheckInterval = setInterval(() => {
handleBattle(opponent);
if (battleCounted) clearInterval(hpCheckInterval);
}, 1000);
const rewardsObserver = new MutationObserver(() => {
const rewardText = document.querySelector('#bd_rewards .rewardstext');
if (rewardText) {
rewardText.style.paddingTop = '0';
const rewardsLoot = document.querySelector('#bd_rewardsloot');
if (rewardsLoot) rewardsLoot.style.height = '100px';
rewardsObserver.disconnect();
}
});
rewardsObserver.observe(document, { childList: true, subtree: true });
}
// Get current opponent name
function getOpponentName() {
const opponentElement = document.querySelector('#p2name');
return opponentElement ? opponentElement.textContent.trim() : 'Unknown Opponent';
}
// Check initial HP status for both participants
function checkInitialHP() {
const p1hp = document.querySelector('#p1hp');
const p2hp = document.querySelector('#p2hp');
if (p1hp && p2hp) {
const p1InitialHP = parseInt(p1hp.textContent.trim(), 10);
const p2InitialHP = parseInt(p2hp.textContent.trim(), 10);
if (p1InitialHP <= 0 || p2InitialHP <= 0) {
console.warn('Battle not counted: Initial HP is 0 for one or both participants.');
return false;
}
}
return true;
}
// Handle the battle detection and counting
function handleBattle(opponent) {
if (battleCounted) return;
const p1hp = document.querySelector('#p1hp');
const p2hp = document.querySelector('#p2hp');
if (p1hp && p2hp) {
const p1hpValue = parseInt(p1hp.textContent.trim(), 10);
const p2hpValue = parseInt(p2hp.textContent.trim(), 10);
// Determine whether to count the battle
if (
(recordWinsOnly && p2hpValue === 0 && p1hpValue > 0) || // Only count wins if recordWinsOnly is true
(!recordWinsOnly && (p1hpValue === 0 || p2hpValue === 0)) // Count all battles if recordWinsOnly is false
) {
battleCounted = true;
// Increment the total battle count
incrementCounter('totalBattleCount');
// Increment obelisk battle count if applicable
if (isObeliskOpponent()) {
incrementCounter('obeliskBattleCount');
localStorage.setItem('obeliskBattleCount-date', new Date().toISOString());
}
// Increment opponent-specific count if applicable
if (opponent !== 'Unknown Opponent') {
const opponentKey = `battleCount-${opponent}`;
const opponentCount = incrementCounter(opponentKey);
updateCounter(opponentKey, opponentCount);
}
// Update the combined counter display
updateCombinedCounter();
}
}
}
cleanupExpiredRecords(); // Run cleanup on script initialization
const observer = new MutationObserver((mutations, me) => {
try {
if (
document.querySelector('#p2name') &&
document.querySelector('.bdPopupGeneric.middle') &&
document.querySelector('#p1hp') &&
document.querySelector('#p2hp')
) {
initializeCounters();
addObeliskContribution(); // Call the function here
me.disconnect();
}
} catch (error) {
console.error('Error in MutationObserver:', error);
}
});
observer.observe(document, { childList: true, subtree: true });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment