NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name CCO Buff Alarm V2
// @namespace CyberCodeOnline
// @version 2.0.1
// @description Simple calibration alert bot for cyber code online
// @author Jefreesujit
// @match https://cybercodeonline.com/tabs/stats
// @icon https://www.google.com/s2/favicons?sz=64&domain=cybercodeonline.com
// @grant none
// @license MIT
// ==/UserScript==
/*jshint esversion: 8 */
(function() {
'use strict';
// bot url endpoint
const hookUrl = 'https://discord.com/api/webhooks/963049861220032582/0560pIXdu5ScAXDLBsbT7xaHkzeuMhn8lEXcE6BDEQvXr2MOwOuvbniJDFsnUR9c8qtrx';
const role = '<@&960109485618241587>';
// buff to be looked for
const buffPrefix = 'calibration';
let messageId, isTimeoutActive = false;
const delay = async (timer = 5000) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(timer);
}, timer);
});
}
// calculate the buff score from percentage
// Contribution credits: Rejid
const getBuffScoreFromPerc = (percent) => {
if (percent>=666){
return "+10 Cali";
}
if (percent>=400){
return "+9 Cali";
}
if (percent>=200){
return "+8 Cali";
}
if (percent>=150){
return "+7 Cali";
}
if (percent>=100){
return "+6 Cali";
}
if (percent>=50){
return "+5 Cali";
}
if (percent>=15){
return "+4 Cali";
}
if (percent>=10){
return "+3 Cali";
}
if (percent>=5){
return "+2 Cali";
}
return "No Cali";
};
// Iterate through each active buffs to check for matching buff name
// Fetch the percentage score for each buff and sum it up
const getBuffPerc = async () => {
let buffVal = 0, buffName = '';
const buffContEl = document.querySelector('.z-10 div.flex-row.flex-wrap.mb-2');
const buffArray = [];
buffContEl.childNodes.forEach((childEl, index) => {
console.log('childEl', childEl);
const buffEl = childEl.childNodes[1];
const bt = buffEl.innerText;
if (bt.toLowerCase().includes(buffPrefix)) {
buffArray.push(childEl);
buffName = bt;
}
});
for (let buffItem of buffArray) {
await delay(1000);
buffItem.childNodes[1].click();
const buffModal = document.querySelector('div.border.neon.p-2.justify-center.items-center.mr-2');
const buffPerc = buffModal ? buffModal.innerText.split('\n').shift() : '0';
buffModal && document.querySelector('.dialog-backdrop').click();
console.log('buffPerc', buffVal);
buffVal += parseInt(buffPerc.replace(/[^0-9]/g,''), 10);
}
console.log('buffVal after for loop', buffVal);
return [buffVal, buffName];
};
// Experimental : Push all events to another events bot
const pushEvents = (eventText) => {
fetch(`${hookUrl}?wait=true`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: eventText })
});
};
// Send message to bot
const sendMessage = async (message) => {
const rawResponse = await fetch(`${hookUrl}?wait=true`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: message })
});
const content = await rawResponse.json();
console.log('response', content);
return content;
};
// Update existing message if messageId already present
const updateMessage = async (message, msgId) => {
const rawResponse = await fetch(`${hookUrl}/messages/${msgId}`, {
method: 'PATCH',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: message })
});
const content = await rawResponse.json();
return content;
};
// Listen for observed dom mutations and check for matching buff names
// Fetch required metadata, construct request payload for sending message to bot
const getMessage = async (mutation) => {
let message = '';
if (mutation.type == 'childList' && mutation.addedNodes.length) {
const newEl = mutation.addedNodes[0];
if (newEl.classList.length === 0) {
const buffText = newEl.innerText;
if (buffText.toLowerCase().includes(buffPrefix)) {
message = `${role} Buff Added `;
const activatedBy = newEl.querySelector('.text-mod').innerText;
try {
const [tBuffPerc, tBuffName] = await getBuffPerc();
const buffScore = getBuffScoreFromPerc(tBuffPerc);
message = `**Buff Name**: *${tBuffName}* \n**Buff Value**: ${buffScore} (estimated)\n**Mentions**: ${role} @here \n**Activated By**: *${activatedBy}*`;
} catch (e) {
console.log('Failed fetching buff percenatage', e);
}
}
console.log(buffText);
// pushEvents(buffText);
}
}
return message;
};
// Callback handler for observed dom mutations
const callback = async (mutationsList) => {
for(let mutation of mutationsList) {
// console.log('buff object', mutation.type, mutation);
const message = await getMessage(mutation);
if (message) {
if (messageId) {
console.log('updateMessage', message, messageId);
const { id } = await updateMessage(message, messageId);
} else {
console.log('sendMessage', message);
const { id } = await sendMessage(message);
messageId = id;
}
}
}
// Persist the messageId for 4 minutes when new matching buff is added.
// Whenever a buff is added within that time, update existing message with this messageId
// Erase the messageId after 4 minutes (active buff time) and push upcoming event as new buffs
if (messageId && !isTimeoutActive) {
isTimeoutActive = true;
setTimeout(() => {
console.log('messageId', messageId)
messageId = null;
isTimeoutActive = false;
}, 240000);
}
};
// Initialise Script after 10 seconds of page load (wait until page loads fully)
setTimeout(() => {
const config = { attributes: false, childList: true, subtree: false, characterData: false };
// Buff observable DOM
const buffContainerEl = document.querySelector('.h-full.relative.flex-col-reverse.overflow-y-scroll.overflow-x-hidden'); // chat window
// const buffContainerEl = document.querySelector('.z-10 div.flex-row.flex-wrap.mb-2'); // buff window
try {
const observer = new MutationObserver(callback);
observer.observe(buffContainerEl, config);
console.log('Buff Observable v2 Initialized');
} catch (e) {
console.log('Buff Observable v2 Initialization error', e);
}
}, 10000);
})();