您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Organizational script for the Criptoe Trading Card Game
当前为
// ==UserScript== // @name IdlePixel TCG Dex (Lux Fork) // @namespace luxferre.dev // @version 0.1.0 // @description Organizational script for the Criptoe Trading Card Game // @author GodofNades & Lux-Ferre // @match *://idle-pixel.com/login/play* // @grant none // @license MIT // @require https://gf.qytechs.cn/scripts/441206-idlepixel/code/IdlePixel+.js?anticache=20220905 // ==/UserScript== (function () { "use strict"; let playername = ""; window.TCG_IMAGE_URL_BASE = document .querySelector("itembox[data-item=copper] img") .src.replace(/\/[^/]+.png$/, "") + "/"; let onLoginLoaded = false; let categoriesTCG = []; let currentCards = []; let overallCardCounts = {}; class tcgDex extends IdlePixelPlusPlugin { constructor() { super("tcgDex", { about: { name: GM_info.script.name + " (ver: " + GM_info.script.version + ")", version: GM_info.script.version, author: GM_info.script.author, description: GM_info.script.description, }, config: [ { label: "------------------------------------------------<br/>Notification<br/>------------------------------------------------", type: "label", }, { id: "tcgNotification", label: "Enable TCG Card Buying Available Notification<br/>(Default: Enabled)", type: "boolean", default: true, }, { id: "newCardTimer", label: "New Card Timer<br/>(How long do you want a card to show as new, in minutes.)", type: "int", default: 15 } ], }); } getCategoryData() { let uniqueDescriptionTitles = []; const descriptionTitlesSet = new Set(); let i = 1; Object.values(CardData.data).forEach((card) => { const descriptionTitle = card["description_title"]; const properTitles = descriptionTitle.charAt(0).toUpperCase() + descriptionTitle.slice(1).toLowerCase(); if (!descriptionTitlesSet.has(descriptionTitle)) { descriptionTitlesSet.add(descriptionTitle); uniqueDescriptionTitles.push({ id: `[${descriptionTitle}]`, desc: descriptionTitle, label: `${i}. ${properTitles}`, }); i++; } }); return uniqueDescriptionTitles; } ensureNewSettingExists() { const settings = JSON.parse(localStorage.getItem(`${playername}.tcgSettings`)); if (settings && typeof settings.new === 'undefined') { settings.new = true; localStorage.setItem(`${playername}.tcgSettings`, JSON.stringify(settings)); } } calculateCardCounts() { let cardCounts = {}; categoriesTCG.forEach((category) => { cardCounts[category.desc] = { uniHolo: 0, ttlHolo: 0, uniNormal: 0, ttlNormal: 0, possHolo: 0, possNormal: 0, possUniHolo: 0, possUniNormal: 0, }; }); overallCardCounts = { overallUniHolo: 0, overallHolo: 0, overallTTL: 0, overallUniNormal: 0, overallNormal:0, } Object.values(CardData.data).forEach((card) => { const category = categoriesTCG.find( (c) => c.id === `[${card.description_title}]` ); if (category) { cardCounts[category.desc].uniHolo++; cardCounts[category.desc].uniNormal++; overallCardCounts.overallTTL++; } }); const uniHoloSetOverall = new Set(); const uniNormalSetOverall = new Set(); currentCards.forEach((card) => { const category = Object.entries(CardData.data).find( (c) => c[0] === card.id ); if (category) { if (card.holo) { cardCounts[category[1].description_title].possHolo++; cardCounts[category[1].description_title].ttlHolo++; overallCardCounts.overallHolo++; if (!uniHoloSetOverall.has(card.id)) { uniHoloSetOverall.add(card.id); overallCardCounts.overallUniHolo++; cardCounts[category[1].description_title].possUniHolo++; } } else { cardCounts[category[1].description_title].possNormal++; cardCounts[category[1].description_title].ttlNormal++; overallCardCounts.overallNormal++; if (!uniNormalSetOverall.has(card.id)) { uniNormalSetOverall.add(card.id); overallCardCounts.overallUniNormal++; cardCounts[category[1].description_title].possUniNormal++; } } } }); return cardCounts; } initializeDatabase() { const dbName = `IdlePixel_TCG_DB.${playername}`; const version = 1; const request = indexedDB.open(dbName, version); request.onerror = (event) => { console.error("Database error: ", event.target.error); }; request.onupgradeneeded = (event) => { const db = event.target.result; const objectStoreName = `current_cards`; if (!db.objectStoreNames.contains(objectStoreName)) { const objectStore = db.createObjectStore(objectStoreName, { keyPath: ["id", "cardNum", "holo"] }); } }; request.onsuccess = (event) => { this.db = event.target.result; }; } fetchAllCardsFromDB(db, objectStoreName, callback) { const transaction = db.transaction([objectStoreName], "readonly"); const objectStore = transaction.objectStore(objectStoreName); const request = objectStore.getAll(); request.onerror = (event) => { console.error("Error fetching cards from DB:", event.target.error); }; request.onsuccess = () => { callback(request.result); }; } identifyAndRemoveAbsentCards(db, objectStoreName, currentCards) { IdlePixelPlus.plugins.tcgDex.fetchAllCardsFromDB(db, objectStoreName, (dbCards) => { const currentCardsKeySet = new Set(currentCards.map(card => JSON.stringify([card.id, card.cardNum, card.holo.toString()]))); dbCards.forEach(dbCard => { const dbCardKey = JSON.stringify([dbCard.id, dbCard.cardNum, dbCard.holo.toString()]); if (!currentCardsKeySet.has(dbCardKey)) { // This card is in the DB but not in the currentCards array, so remove it from the DB IdlePixelPlus.plugins.tcgDex.removeCardFromDB(db, objectStoreName, [dbCard.id, dbCard.cardNum, dbCard.holo]); } }); }); } removeCardFromDB(db, objectStoreName, cardKey) { const transaction = db.transaction([objectStoreName], "readwrite"); const objectStore = transaction.objectStore(objectStoreName); const request = objectStore.delete(cardKey); request.onerror = (event) => { console.error("Error removing card from DB:", event.target.error); }; request.onsuccess = () => { console.log(`Card removed from DB: ${cardKey}`); }; } updateTcgSettings(categoryId, state) { const settings = JSON.parse( localStorage.getItem(`${playername}.tcgSettings`) ); settings[categoryId] = state; localStorage.setItem( `${playername}.tcgSettings`, JSON.stringify(settings) ); } getTcgSetting(categoryId) { const settings = JSON.parse( localStorage.getItem(`${playername}.tcgSettings`) ); return settings[categoryId]; } tcgBuyerNotifications() { let tcgTimerCheck = IdlePixelPlus.getVarOrDefault("tcg_timer", 0, "int"); let tcgUnlocked = IdlePixelPlus.getVarOrDefault("tcg_active", 0, "int"); const notifDiv = document.createElement("div"); notifDiv.id = `notification-tcg-timer`; notifDiv.onclick = function () { websocket.send(switch_panels("panel-criptoe-tcg")); websocket.send(Modals.open_buy_tcg()); }; notifDiv.className = "notification hover"; notifDiv.style = "margin-right: 4px; margin-bottom: 4px; display: none"; notifDiv.style.display = "inline-block"; let elem = document.createElement("img"); elem.setAttribute("src", `${TCG_IMAGE_URL_BASE}ash_50.png`); const notifIcon = elem; notifIcon.className = "w20"; const notifDivLabel = document.createElement("span"); notifDivLabel.id = `notification-tcg-timer-label`; notifDivLabel.innerText = " Loading..."; notifDivLabel.className = "color-white"; notifDiv.append(notifIcon, notifDivLabel); document.querySelector("#notifications-area").prepend(notifDiv); if (tcgUnlocked == 0 || !this.getConfig("tcgNotification")) { document.querySelector("#notification-tcg-timer").style.display = "none"; } } updateTCGNotification() { let tcgTimerCheck = IdlePixelPlus.getVarOrDefault("tcg_timer", 0, "int"); let tcgUnlocked = IdlePixelPlus.getVarOrDefault("tcg_active", 0, "int"); if (this.getConfig("tcgNotification") && tcgUnlocked != 0) { document.getElementById("notification-tcg-timer").style.display = "inline-block"; if (tcgTimerCheck > 0) { let timerLabel = format_time(tcgTimerCheck); document.getElementById( "notification-tcg-timer-label" ).innerText = ` ${timerLabel}`; } else { document.getElementById( "notification-tcg-timer-label" ).innerText = ` Time to buy cards!`; } } else { document.getElementById("notification-tcg-timer").style.display = "none"; } } onLogin() { const card_template_str = ` <template id="tcg_card_template"> <div onclick="Modals.open_tcg_give_card(null, this.getAttribute('data-card-id'))" data-card-id="" style="" class='tcg-card hover'> <div class="tcg-card-title"> <span class="tcg_card_label"></span> </div> <div class='tcg-card-inner'> <img alt="" src="" class='w50'> </div> <div class='tcg-card-inner-text'>" <b class="tcg_card_description"></b> <br> <br> <span class="tcg_card_zalgo"> 𓀚𓁁𓂧𓃢𓃴𓄜𓈤𓈤𓊙𓐈𓀚𓁁𓂧𓃢𓃴<br>𓄜𓈤𓈤𓊙𓐈𓀚𓁁𓂧𓃢𓃴𓄜𓈤𓈤𓊙𓐈<br>𓀚𓁁𓂧𓃢𓃴𓄜𓈤𓈤𓊙𓐈𓀚𓁁𓂧𓃢𓃴<br>𓄜𓈤𓈤𓊙𓐈𓀚𓁁𓂧𓃢𓃴𓄜𓈤𓈤𓊙𓐈 </span> </div> </div> </template> ` $("body").append($(card_template_str)) CardData.fetchData() CToe.loadCards = function () {}; playername = IdlePixelPlus.getVarOrDefault("username", "", "string"); setTimeout(() => { categoriesTCG = this.getCategoryData(); if (!localStorage.getItem(`${playername}.tcgSettings`)) { let defaultSettings = categoriesTCG.reduce((settings, category) => { settings[category.desc] = true; return settings; }, {}); defaultSettings.new = true; localStorage.setItem( `${playername}.tcgSettings`, JSON.stringify(defaultSettings) ); } else { IdlePixelPlus.plugins.tcgDex.ensureNewSettingExists(); } this.initializeDatabase(); this.tcgBuyerNotifications(); this.updateTCGNotification(); onLoginLoaded = true; }, 1000); } onVariableSet(key, valueBefore, valueAfter) { if (onLoginLoaded) { if (key.startsWith("tcg") && valueBefore != valueAfter) { IdlePixelPlus.plugins.tcgDex.updateTCGNotification(); } } } onConfigChange() { if (onLoginLoaded) { IdlePixelPlus.plugins.tcgDex.updateTCGNotification(); } } onMessageReceived(data) { if (data.startsWith("REFRESH_TCG")) { const parts = data.replace("REFRESH_TCG=", "").split("~"); let cardSort = []; currentCards = []; let order = 1; let newCards = []; Object.keys(CardData.data).forEach((key) => { cardSort.push({ id: key, order: order++, holo: true }); cardSort.push({ id: key, order: order++, holo: false }); }); for (let i = 0; i < parts.length; i += 3) { const cardNum = parts[i]; const cardKey = parts[i + 1]; const isHolo = parts[i + 2] === "true"; const matchingCard = cardSort.find( (card) => card.id === cardKey && card.holo === isHolo ); if (matchingCard) { currentCards.push({ id: cardKey, cardNum: cardNum, holo: isHolo, order: matchingCard.order, }); } } currentCards.sort((a, b) => a.order - b.order); const objectStoreName = `current_cards`; const transaction = this.db.transaction([objectStoreName], "readwrite"); const objectStore = transaction.objectStore(objectStoreName); currentCards.forEach((card) => { const key = [card.id, card.cardNum, card.holo.toString()]; const getRequest = objectStore.get(key); getRequest.onsuccess = (event) => { let result = event.target.result; if (result) { let now = new Date(); let timeBefore = new Date(now.getTime() - (15*60*1000)); let receivedDateTime = new Date(result.received_datetime); if (receivedDateTime > timeBefore) { newCards.push({ cardNum: result.cardNum, id: result.id, holo: result.holo, received_datetime: receivedDateTime }); } } else { const cardData = { id: card.id.toString(), cardNum: card.cardNum.toString(), holo: card.holo.toString(), received_datetime: new Date().toISOString(), }; const addRequest = objectStore.add(cardData); addRequest.onerror = (event) => { console.error("Error adding new card:", event.target.error); }; addRequest.onsuccess = (event) => { }; newCards.push({ cardNum: card.cardNum.toString(), id: card.id.toString(), holo: card.holo.toString(), received_datetime: new Date().toISOString(), }); } }; getRequest.onerror = (event) => { console.error("Error fetching card record:", event.target.error); }; }); IdlePixelPlus.plugins.tcgDex.identifyAndRemoveAbsentCards(this.db, `current_cards`, currentCards); document.getElementById("tcg-area-context").innerHTML = "" const template = document.getElementById("tcg_card_template") let card_container_frag = document.createDocumentFragment() for (const card of Object.values(currentCards)) { const id = card.cardNum const holo = card.holo const card_data = CardData.data[card.id] let clone = template.content.cloneNode(true) let tcg_outer = clone.querySelector(".tcg-card") tcg_outer.setAttribute("data-card-id", id) const styles = `${card_data.border_css}${card_data.background_css}` tcg_outer.setAttribute("style", styles) clone.querySelector(".tcg_card_label").innerText = card_data.label clone.querySelector("img").setAttribute("src", `https://cdn.idle-pixel.com/images/${card_data.image}`) clone.querySelector(".tcg_card_description").innerText = card_data.description_title if(holo){ clone.querySelector(".tcg-card-inner").classList.add("holo") clone.querySelector(".tcg_card_zalgo").classList.add("shine") } else { clone.querySelector(".tcg_card_zalgo").classList.add("color-grey") } card_container_frag.appendChild(clone) } document.getElementById("tcg-area-context").appendChild(card_container_frag) card_container_frag.innerHTML = "" const pendingTCGContainer = document.getElementById("tcg-area-context"); const cardOverallStatsLabel = document.createElement("span"); const ttlOverallCardsLabel = document.createElement("span"); ttlOverallCardsLabel.id = "ttl-overall-cards-label"; ttlOverallCardsLabel.style.marginLeft = "60px"; const uniOverallHoloLabel = document.createElement("span"); uniOverallHoloLabel.id = "uni-overall-holo-label"; const ttlOverallHoloLabel = document.createElement("span"); ttlOverallHoloLabel.id = "ttl-overall-holo-label"; const uniOverallNormalLabel = document.createElement("span"); uniOverallNormalLabel.id = "uni-overall-normal-label"; const ttlOverallNormalLabel = document.createElement("span"); ttlOverallNormalLabel.id = "ttl-overall-normal-label"; cardOverallStatsLabel.appendChild(ttlOverallCardsLabel); cardOverallStatsLabel.appendChild(uniOverallHoloLabel); cardOverallStatsLabel.appendChild(ttlOverallHoloLabel); cardOverallStatsLabel.appendChild(uniOverallNormalLabel); cardOverallStatsLabel.appendChild(ttlOverallNormalLabel); pendingTCGContainer.appendChild(cardOverallStatsLabel); pendingTCGContainer.appendChild(document.createElement("br")); pendingTCGContainer.appendChild(document.createElement("br")); const categoryNewDiv = document.createElement("div"); categoryNewDiv.id = `pendingNewContainer`; const categoryNewDivInner = document.createElement("div"); categoryNewDivInner.id = `pendingNewContainerInner`; categoryNewDivInner.style.display = IdlePixelPlus.plugins.tcgDex.getTcgSetting("new")? "": "none"; const toggleButtonNew = document.createElement("button"); toggleButtonNew.textContent = IdlePixelPlus.plugins.tcgDex.getTcgSetting("new")? " ↥ ": " ↧ "; toggleButtonNew.style.width = "50px"; toggleButtonNew.style.marginRight = "10px"; toggleButtonNew.addEventListener("click", () => { const isVisible = categoryNewDivInner.style.display !== "none"; categoryNewDivInner.style.display = isVisible ? "none" : ""; toggleButtonNew.textContent = isVisible ? " ↧ " : " ↥ "; IdlePixelPlus.plugins.tcgDex.updateTcgSettings("new",!isVisible); }); const newCardTimer = IdlePixelPlus.plugins.tcgDex.getConfig("newCardTimer"); const labelSpanNew = document.createElement("span"); labelSpanNew.textContent = `New Cards (Last ${newCardTimer} Mins)`; categoryNewDiv.appendChild(toggleButtonNew); categoryNewDiv.appendChild(labelSpanNew); categoryNewDiv.appendChild(document.createElement("br")); categoryNewDiv.appendChild(document.createElement("br")); categoryNewDiv.appendChild(categoryNewDivInner); document.getElementById("tcg-area-context").appendChild(categoryNewDiv); categoriesTCG.forEach((category) => { const categoryDiv = document.createElement("div"); categoryDiv.id = `pending${category.desc}Container`; const categoryDivInner = document.createElement("div"); categoryDivInner.id = `pending${category.desc}ContainerInner`; categoryDivInner.style.display = IdlePixelPlus.plugins.tcgDex.getTcgSetting(category.desc) ? "" : "none"; const toggleButton = document.createElement("button"); toggleButton.textContent = IdlePixelPlus.plugins.tcgDex.getTcgSetting( category.desc ) ? " ↥ " : " ↧ "; toggleButton.style.width = "50px"; toggleButton.style.marginRight = "10px"; toggleButton.addEventListener("click", () => { const isVisible = categoryDivInner.style.display !== "none"; categoryDivInner.style.display = isVisible ? "none" : ""; toggleButton.textContent = isVisible ? " ↧ " : " ↥ "; IdlePixelPlus.plugins.tcgDex.updateTcgSettings( category.desc, !isVisible ); }); categoryDiv.innerHTML = ` <div id="tcgLabel" style="font-size: 1.25em"></div> `; categoryDiv.appendChild(toggleButton); const labelSpan = document.createElement("span"); labelSpan.textContent = category.label; categoryDiv.appendChild(toggleButton); categoryDiv.appendChild(labelSpan); const cardStatsLabel = document.createElement("span"); const ttlCardsLabel = document.createElement("span"); ttlCardsLabel.id = "ttl-cards-label"; ttlCardsLabel.style.marginLeft = "60px"; const uniHoloLabel = document.createElement("span"); uniHoloLabel.id = "uni-holo-label"; const ttlHoloLabel = document.createElement("span"); ttlHoloLabel.id = "ttl-holo-label"; const uniNormalLabel = document.createElement("span"); uniNormalLabel.id = "uni-normal-label"; const ttlNormalLabel = document.createElement("span"); ttlNormalLabel.id = "ttl-normal-label"; cardStatsLabel.appendChild(ttlCardsLabel); cardStatsLabel.appendChild(uniHoloLabel); cardStatsLabel.appendChild(ttlHoloLabel); cardStatsLabel.appendChild(uniNormalLabel); cardStatsLabel.appendChild(ttlNormalLabel); categoryDiv.appendChild(document.createElement("br")); categoryDiv.appendChild(cardStatsLabel); categoryDiv.appendChild(document.createElement("br")); categoryDiv.appendChild(categoryDivInner); document.getElementById("tcg-area-context").appendChild(categoryDiv); }); const cardCounts = this.calculateCardCounts(); categoriesTCG.forEach((category) => { const counts = cardCounts[category.desc]; document.querySelector( `#pending${category.desc}Container #ttl-cards-label` ).textContent = `Total Cards (${ counts.possHolo + counts.possNormal })`; document.querySelector( `#pending${category.desc}Container #uni-holo-label` ).textContent = ` => Holo: [ Unique: (${counts.possUniHolo}/${counts.uniHolo})`; document.querySelector( `#pending${category.desc}Container #ttl-holo-label` ).textContent = ` || Total: (${counts.ttlHolo}) ]`; document.querySelector( `#pending${category.desc}Container #uni-normal-label` ).textContent = ` Normal: [ Unique: (${counts.possUniNormal}/${counts.uniNormal})`; document.querySelector( `#pending${category.desc}Container #ttl-normal-label` ).textContent = ` || Total: (${counts.ttlNormal}) ]`; }); document.getElementById(`ttl-overall-cards-label`).textContent = `Total Cards (${overallCardCounts.overallHolo + overallCardCounts.overallNormal})`; document.getElementById(`uni-overall-holo-label`).textContent = ` => Holo: [ Unique: (${overallCardCounts.overallUniHolo}/${overallCardCounts.overallTTL})`; document.getElementById(`ttl-overall-holo-label`).textContent = ` || Total: (${overallCardCounts.overallHolo}) ]`; document.getElementById(`uni-overall-normal-label`).textContent = ` Normal: [ Unique: (${overallCardCounts.overallUniNormal}/${overallCardCounts.overallTTL})`; document.getElementById(`ttl-overall-normal-label`).textContent = ` || Total: (${overallCardCounts.overallNormal}) ]`; document.querySelectorAll(".tcg-card").forEach((card) => { categoriesTCG.forEach((category) => { if (card.textContent.includes(category.id)) { document .getElementById(`pending${category.desc}ContainerInner`) .appendChild(card); } }); }); setTimeout(() => { newCards.sort((a, b) => b.received_datetime - a.received_datetime); const newCardsJoinedString = newCards.map((card) => `${card.cardNum}~${card.id}~${card.holo}`).join("~"); document.getElementById("pendingNewContainerInner").innerHTML = ""; if (newCardsJoinedString == "") return; var dataArrayNew = newCardsJoinedString.split("~"); var htmlNew = ""; for (var ix = 0; ix < dataArrayNew.length; ) { var idNew = dataArrayNew[ix++]; var var_nameNew = dataArrayNew[ix++]; var holoNew = dataArrayNew[ix++] == "true"; htmlNew += CardData.getCardHTML(idNew, var_nameNew, holoNew); } document.getElementById("pendingNewContainerInner").innerHTML = htmlNew; },2000); } } } const plugin = new tcgDex(); IdlePixelPlus.registerPlugin(plugin); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址