您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Improved interface for opening new cards, receiving cards in trade & trading cards
// ==UserScript== // @name IdlePixel+ New Card Interface // @namespace lbtechnology.info // @version 1.2.3 // @description Improved interface for opening new cards, receiving cards in trade & trading cards // @author Zlef // @license MIT // @match *://idle-pixel.com/login/play* // @grant none // @icon https://d1xsc8x7nc5q8t.cloudfront.net/images/tcg_back_50.png // @require https://greasyfork.org/scripts/441206-idlepixel/code/IdlePixel+.js?anticache=20220905 // ==/UserScript== (function() { 'use strict'; class TCGRevamp extends IdlePixelPlusPlugin { constructor() { super("TCG Interface Changes", { about: { name: GM_info.script.name, version: GM_info.script.version, author: GM_info.script.author, description: GM_info.script.description } }); this.showPopup = false; this.messageStart = "You got a" this.trade = false; this.card = ""; this.refreshTCG = ""; this.currentPopup = null; this.savedUsernamesTCG = null; this.previousTradeUsername = null; this.inCombat = false; this.inCombatTrade = false; this.loadUsernames(); this.overlay = document.createElement('div'); this.overlay.id = 'newCardOverlay'; this.overlay.style.position = 'fixed'; this.overlay.style.top = '0'; this.overlay.style.left = '0'; this.overlay.style.width = '100%'; this.overlay.style.height = '100%'; this.overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; this.overlay.style.zIndex = '1000'; this.overlay.style.display = 'flex'; this.overlay.style.justifyContent = 'center'; this.overlay.style.alignItems = 'center'; this.overlay.addEventListener('click', (event) => { if (event.target === this.overlay) { this.closePopup(); } }); window.addEventListener('resize', this.adjustPopupPosition.bind(this)); } onLogin() { this.originalTcgGiveCard = Modals.open_tcg_give_card; Modals.open_tcg_give_card = (modal_id, card) => { if (!modal_id) { this.newTradePopup(card); } else { this.originalTcgGiveCard(modal_id, card); } }; if (!CardData.data) { CardData.fetchData(); } this.monitorRevealTCG(); } saveUsernames(){ const saveData = JSON.stringify({usernames: this.savedUsernamesTCG}); localStorage.setItem(`savedUsernamesTCG`, saveData); } loadUsernames(){ const savedUsernamesTCG = localStorage.getItem(`savedUsernamesTCG`); if (savedUsernamesTCG){ this.savedUsernamesTCG = JSON.parse(savedUsernamesTCG).usernames; } else { this.savedUsernamesTCG = []; } } monitorRevealTCG() { const originalWebSocketSend = WebSocket.prototype.send; const self = this; WebSocket.prototype.send = function(data) { try { originalWebSocketSend.call(this, data); if (data === 'REVEAL_TCG_CARD') { self.showPopup = true; } } catch (error) { console.error('Error in overridden WebSocket send:', error); } }; } onMessageReceived(data){ const originalOpenImageModal = Modals.open_image_modal; const self = this; if (data.includes("OPEN_DIALOGUE")){ console.log("Open dialogue message received"); Modals.open_image_modal = function(title, imgUrl, description, footerText, closeBtnText, anotherBtnText, isModalDismissible) { if (description.includes("You were given a card from")) { console.log("Opening custom dialogue"); const usernameRegex = /You were given a card from (.*?)<br \/>/; const cardRegex = /<span class='color-grey'>(.*?)<\/span>/; const usernameMatch = description.match(usernameRegex); const cardMatch = description.match(cardRegex); let username = ""; let card = ""; if (usernameMatch && usernameMatch.length > 1) { username = usernameMatch[1]; } if (cardMatch && cardMatch.length > 1) { self.card = cardMatch[1]; } self.messageStart = `${username} sent you a`; self.trade = true; self.showPopup = true; } else { console.log("Opening original dialogue"); originalOpenImageModal.call(this, title, imgUrl, description, footerText, closeBtnText, anotherBtnText, isModalDismissible); } }; } if (data.includes("REFRESH_TCG")){ this.refreshTCG = data; // console.log("In REFRESH_TCG, checking for inCombat"); if (this.trade && this.inCombat){ this.showPopup = false; this.inCombatTrade = true; // console.log("inCombatTrade set to True"); } if (this.showPopup){ if (this.trade){ this.getCardInfo(); this.trade = false; this.card = ""; } else { this.getCardInfo(); } this.showPopup = false; this.messageStart = "You got a"; } } if (data.includes('START_RAID')){ this.inCombat = true; // console.log("In raid"); } if (data.includes('RAIDS_TEAM_INFO_DESTROYED') || data.includes('RAIDS REWARD')){ // console.log("Exited raid"); this.inCombat = false; if (this.inCombatTrade){ // console.log("inCombatTrade is true, opening modal"); this.inCombatTrade = false; this.openSimplePopup("Trading Card Game", "You received card(s) during in combat!"); } } } onCombatStart(){ this.inCombat = true; } onCombatEnd(){ this.inCombat = false; if (this.inCombatTrade){ this.inCombatTrade = false; this.openSimplePopup("Trading Card Game", "You received card(s) during in combat!"); } } getCardInfoTrade(cardid) { const cardData = this.refreshTCG.replace('REFRESH_TCG=', '').split('~'); const index = cardData.indexOf(cardid); const isThisYourCard = [cardData[index], cardData[index + 1], cardData[index + 2]]; const isHolo = isThisYourCard[2] === 'true'; const cardHTML = CardData.getCardHTML(isThisYourCard[0], isThisYourCard[1], isHolo); return cardHTML; } getCardInfo() { const cardData = this.refreshTCG.replace('REFRESH_TCG=', '').split('~'); let isHolo = 'false'; if (this.trade) { const cardName = this.card.replace(/ \(holo\)$/, ''); const index = cardData.indexOf(cardName); if (index !== -1) { const id = cardData[index - 1]; const nameKey = cardData[index]; const holo = cardData[index + 1]; isHolo = this.card.includes("(holo)") ? 'true' : holo; this.displayNewCard(id, nameKey, isHolo); } } else { if (cardData.length >= 3) { const id = cardData[0]; const nameKey = cardData[1]; isHolo = cardData[2]; this.displayNewCard(id, nameKey, isHolo); } } } getCardInfoUnified(cardPart, identifier) { const cardData = this.refreshTCG.replace('REFRESH_TCG=', '').split('~'); const index = cardData.indexOf(identifier); let id, nameKey, holo, isHolo; if (identifier === 'card_id') { id = cardPart; nameKey = cardData[index + 1]; holo = cardData[index + 2]; } else if (identifier === 'card_key') { id = cardData[index - 1]; nameKey = cardPart; holo = cardData[index + 1]; if (this.isTrade) { nameKey = this.refactorCardKey(nameKey); holo = this.card.includes("(holo)") ? 'true' : holo; } } else { console.error('Invalid card target type'); return; } isHolo = (holo === 'true'); this.displayNewCard(id, nameKey, isHolo); } displayNewCard(cardId, cardNameKey, holo) { const cardName = cardNameKey.replace('tcg_', '').replace(/_/g, ' ').replace(" icon", ""); const isHolo = holo === 'true'; let bloodyVowels = ""; const vowels = ['a', 'e', 'i', 'o', 'u']; if (vowels.some(vowel => cardName.toLowerCase().startsWith(vowel))) { bloodyVowels = "n"; } const message = isHolo ? `${this.messageStart} holo ${cardName} card!` : `${this.messageStart}${bloodyVowels} ${cardName} card!`; const cardHTML = CardData.getCardHTML(cardId, cardNameKey, isHolo); this.newCardOverlay(message, cardHTML); } updateUserListDisplay() { this.userListContainer.innerHTML = ''; const table = document.createElement('table'); table.className = 'table table-hover'; const thead = document.createElement('thead'); thead.innerHTML = '<tr><th scope="col">Saved users</th><th scope="col"></th></tr>'; table.appendChild(thead); const tbody = document.createElement('tbody'); table.appendChild(tbody); const usernames = this.savedUsernamesTCG; const minimumRows = 0; const rowsToCreate = Math.max(minimumRows, usernames.length); for (let i = 0; rowsToCreate > i; i++) { const tr = document.createElement('tr'); const usernameCell = document.createElement('td'); usernameCell.style.cursor = 'pointer'; usernameCell.style.verticalAlign = 'middle'; usernameCell.style.fontSize = '1.2em'; usernameCell.addEventListener('click', () => { const usernameInput = document.getElementById('recipientUsernameInput'); if (usernameInput) { usernameInput.value = usernames[i]; } }); const actionCell = document.createElement('td'); actionCell.align = "right"; actionCell.style.width = '80px'; if (i < usernames.length) { usernameCell.textContent = usernames[i]; const deleteButton = document.createElement('button'); deleteButton.textContent = 'Delete'; deleteButton.className = 'btn btn-danger btn-sm'; deleteButton.style.padding = '5px 10px'; deleteButton.style.height = 'auto'; deleteButton.onclick = () => this.deleteUsername(usernames[i]); actionCell.appendChild(deleteButton); } tr.appendChild(usernameCell); tr.appendChild(actionCell); tbody.appendChild(tr); } this.userListContainer.appendChild(table); } deleteUsername(username) { const index = this.savedUsernamesTCG.indexOf(username); if (index !== -1) { this.savedUsernamesTCG.splice(index, 1); this.saveUsernames(); this.updateUserListDisplay(); } } newTradePopup(card) { const cardHTML = this.getCardInfoTrade(card).replace(/onclick='[^']+'/g, ''); const tradePopupStyles = ` <style> #tradePopup { display: flex; flex-direction: column; align-items: center; width: 100%; max-width: 800px; margin: 0 auto; background-color: #fff; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); padding: 20px; box-sizing: border-box; } #tradePopup .tradePopup-row { display: flex; width: 100%; } #tradePopup .tradePopup-col { flex: 1; box-sizing: border-box; } #tradePopup .tradePopup-card-container { flex: none; width: 35%; } #tradePopup .tradePopup-button-container { display: flex; justify-content: right; width: 100%; } #tradePopup button { padding: 10px 20px; cursor: pointer; margin-right: 10px; } #userListContainer { max-height: 230px; overflow-y: auto; } </style> `; document.head.insertAdjacentHTML('beforeend', tradePopupStyles); const popupBox = document.createElement('div'); popupBox.id = 'tradePopup'; const rowDiv = document.createElement('div'); rowDiv.className = 'tradePopup-row'; popupBox.appendChild(rowDiv); const cardColDiv = document.createElement('div'); cardColDiv.className = 'tradePopup-col tradePopup-card-container'; rowDiv.appendChild(cardColDiv); const formColDiv = document.createElement('div'); formColDiv.className = 'tradePopup-col'; rowDiv.appendChild(formColDiv); const cardContainer = document.createElement('div'); cardContainer.innerHTML = cardHTML; cardColDiv.appendChild(cardContainer); const title = document.createElement('h5'); title.textContent = "Who do you want to send this card to?"; title.className = "modal-title"; formColDiv.appendChild(title); const inputGroup = document.createElement('div'); inputGroup.className = 'input-group mb-3'; const usernameInput = document.createElement('input'); usernameInput.type = 'text'; usernameInput.className = 'form-control'; usernameInput.id = 'recipientUsernameInput'; usernameInput.placeholder = 'Enter username'; if (this.previousTradeUsername){ usernameInput.value = this.previousTradeUsername; } inputGroup.appendChild(usernameInput); const addUserButton = document.createElement('button'); addUserButton.textContent = 'SAVE USER'; addUserButton.className = 'btn btn-secondary'; addUserButton.type = 'button'; inputGroup.appendChild(addUserButton); formColDiv.appendChild(inputGroup); this.userListContainer = document.createElement('div'); this.userListContainer.id = 'userListContainer'; formColDiv.appendChild(this.userListContainer); this.updateUserListDisplay(); const sendCardButton = document.createElement('button'); sendCardButton.textContent = 'SEND CARD'; sendCardButton.className = 'btn btn-primary'; sendCardButton.type = 'button'; const closeButton = document.createElement('button'); closeButton.textContent = 'CLOSE'; closeButton.className = 'btn btn-secondary'; closeButton.type = 'button'; const buttonContainer = document.createElement('div'); buttonContainer.className = 'tradePopup-button-container'; buttonContainer.appendChild(sendCardButton); buttonContainer.appendChild(closeButton); popupBox.appendChild(buttonContainer); const actions = [ { button: sendCardButton, handler: () => { const recipientUsername = usernameInput.value.trim(); this.previousTradeUsername = recipientUsername; IdlePixelPlus.sendMessage(`GIVE_TCG_CARD=${recipientUsername}~${card}`); } }, { button: closeButton, handler: () => { this.closePopup(); }, closeOnAction: true }, { button: addUserButton, handler: () => { const username = usernameInput.value; if (username && !this.savedUsernamesTCG.includes(username)) { this.savedUsernamesTCG.push(username); this.saveUsernames(); this.updateUserListDisplay(); } }, closeOnAction: false } ]; this.launchPopup(popupBox, actions); } newCardOverlay(message, cardHTML) { const popupBox = document.createElement('div'); popupBox.id = 'newCardPopupBox'; popupBox.style.width = '300px'; popupBox.style.margin = '0 auto'; popupBox.style.backgroundColor = '#fff'; popupBox.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)'; popupBox.style.borderRadius = '8px'; popupBox.style.padding = '20px'; popupBox.style.textAlign = 'center'; const messageP = document.createElement('p'); messageP.textContent = message; messageP.style.fontSize = '18px'; messageP.style.fontWeight = 'bold'; const cardContainer = document.createElement('div'); cardContainer.innerHTML = cardHTML; cardContainer.firstChild.style.marginTop = '0px'; const cardTitle = cardContainer.querySelector('.tcg-card-title'); const cardInnerText = cardContainer.querySelector('.tcg-card-inner-text'); if (cardTitle) { cardTitle.style.textAlign = 'left'; } if (cardInnerText) { cardInnerText.style.textAlign = 'left'; } const openAnotherButton = document.createElement('button'); openAnotherButton.textContent = 'OPEN ANOTHER'; openAnotherButton.style.padding = '10px 20px'; openAnotherButton.style.fontSize = '16px'; openAnotherButton.style.cursor = 'pointer'; openAnotherButton.style.marginRight = '10px'; const tcg_unknown = IdlePixelPlus.getVarOrDefault("tcg_unknown", 0, "int"); openAnotherButton.disabled = tcg_unknown == 1; const closeButton = document.createElement('button'); closeButton.textContent = 'CLOSE'; closeButton.style.padding = '10px 20px'; closeButton.style.fontSize = '16px'; closeButton.style.cursor = 'pointer'; const actions = [ { button: openAnotherButton, handler: () => { IdlePixelPlus.sendMessage("REVEAL_TCG_CARD"); } }, { button: closeButton, handler: () => { this.closePopup(); }, closeOnAction: true } ]; popupBox.appendChild(messageP); popupBox.appendChild(cardContainer); if (!this.trade) { popupBox.appendChild(openAnotherButton); } popupBox.appendChild(closeButton); this.trade = false; this.launchPopup(popupBox, actions); } openSimplePopup(message, footer) { const popupBox = document.createElement('div'); popupBox.style.width = '300px'; popupBox.style.margin = '0 auto'; popupBox.style.backgroundColor = '#fff'; popupBox.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)'; popupBox.style.borderRadius = '8px'; popupBox.style.padding = '20px'; popupBox.style.textAlign = 'center'; const messageP = document.createElement('p'); messageP.textContent = message; messageP.style.fontSize = '18px'; messageP.style.fontWeight = 'bold'; const footerP = document.createElement('p'); footerP.textContent = footer; footerP.style.fontSize = '16px'; const closeButton = document.createElement('button'); closeButton.textContent = 'CLOSE'; closeButton.style.padding = '10px 20px'; closeButton.style.fontSize = '16px'; closeButton.style.cursor = 'pointer'; closeButton.addEventListener('click', () => { this.closePopup(); }); popupBox.appendChild(messageP); popupBox.appendChild(footerP); popupBox.appendChild(closeButton); this.launchPopup(popupBox, []); } launchPopup(popup, actions) { if (this.currentPopup) { if (this.overlay.contains(this.currentPopup)) { this.overlay.removeChild(this.currentPopup); } this.currentPopup = null; } this.currentPopup = popup; this.overlay.appendChild(popup); document.body.appendChild(this.overlay); this.adjustPopupPosition(); actions.forEach(action => { const button = action.button; button.addEventListener('click', () => { action.handler(); if (action.closeOnAction !== false) { this.closePopup(); } }); }); } adjustPopupPosition() { if (!this.currentPopup) return; const viewportHeight = window.innerHeight; const popupHeight = this.currentPopup.offsetHeight; const scrollOffset = window.pageYOffset || document.documentElement.scrollTop; const topPosition = (viewportHeight - popupHeight) / 2 + scrollOffset; this.currentPopup.style.position = 'absolute'; this.currentPopup.style.top = `${topPosition > 0 ? topPosition : 0}px`; } closePopup() { if (this.overlay.contains(this.currentPopup)) { this.overlay.removeChild(this.currentPopup); } document.body.removeChild(this.overlay); this.currentPopup = null; } } const plugin = new TCGRevamp(); IdlePixelPlus.registerPlugin(plugin); })();