您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
HackerWars Clan Shop
// ==UserScript== // @name HW: Clan Shop // @namespace http://tampermonkey.net/ // @version 1.5 // @description HackerWars Clan Shop // @match https://hackerwars.io/clan // @match https://hackerwars.io/clan?id=* // @author Nacom // @grant none // @run-at document-idle // @license MIT // ==/UserScript== (function() { 'use strict'; const PROCESSED_ATTR = 'data-hw-shop-parsed'; const cart = []; const style = document.createElement('style'); style.textContent = ` @keyframes rainbow { 0%{color:red} 16%{color:orange} 33%{color:yellow} 50%{color:green} 66%{color:blue} 83%{color:indigo} 100%{color:violet} } .rainbow-text{animation:rainbow 2s linear infinite} `; document.head.appendChild(style); function findClanDescriptionElement() { const titleEls = Array.from(document.querySelectorAll('.widget-box .widget-title h5')); const descTitle = titleEls.find(h => h.textContent.trim() === 'Clan description'); if(!descTitle) return null; const widgetBox = descTitle.closest('.widget-box'); if(!widgetBox) return null; return widgetBox.querySelector('.widget-content.padding') || null; } function parseDescription(text) { const result = { owner:null, products:[] }; const ownerMatch = text.match(/shopowner\s*:\s*(\S+)/i); if(ownerMatch) result.owner = ownerMatch[1]; const softwareMatch = text.match(/software\s*:\s*([\s\S]*)/i); if(!softwareMatch) return result; const productRegex = /- ([^\(\n]+)\(([^)]+)\)/g; let match; while((match = productRegex.exec(softwareMatch[1]))!==null){ const prodName = match[1].trim(); const versions = match[2].trim().split(',').map(v=>{ const [name, price] = v.split(':'); return { name:name.trim(), price:parseFloat(price) }; }); result.products.push({ name:prodName, versions }); } return result; } function formatPrice(num){ return num.toFixed(3).replace(/\B(?=(\d{3})+(?!\d))/g,'.'); } function processDescription(text){ let html = text.replace(/NCSS!Break/gi,'<br>'); html = html.replace(/\?rainbow!(.*?)!rainbow\?/gs,'<span class="rainbow-text">$1</span>'); html = html.replace(/\?(red|blue|green|yellow|purple|orange)!(.*?)!\1\?/gs,(m,color,content)=>`<span style="color:${color}">${content}</span>`); return html; } function createCartWidget(shopWrapper){ const cartWidget = document.createElement('div'); cartWidget.style.position='absolute'; cartWidget.style.top='10px'; cartWidget.style.right='10px'; cartWidget.style.width='32px'; cartWidget.style.height='32px'; cartWidget.style.cursor='pointer'; const icon = document.createElement('div'); icon.textContent='🛒'; icon.style.fontSize='28px'; icon.style.position='relative'; cartWidget.appendChild(icon); const countBubble = document.createElement('span'); countBubble.textContent='0'; countBubble.style.position='absolute'; countBubble.style.top='-6px'; countBubble.style.right='-6px'; countBubble.style.background='red'; countBubble.style.color='white'; countBubble.style.borderRadius='50%'; countBubble.style.width='18px'; countBubble.style.height='18px'; countBubble.style.fontSize='12px'; countBubble.style.textAlign='center'; countBubble.style.lineHeight='18px'; icon.appendChild(countBubble); const tooltip=document.createElement('div'); tooltip.style.position='absolute'; tooltip.style.top='36px'; tooltip.style.right='0'; tooltip.style.width='220px'; tooltip.style.background='#fff'; tooltip.style.border='1px solid #ccc'; tooltip.style.borderRadius='6px'; tooltip.style.padding='8px'; tooltip.style.boxShadow='0 1px 4px rgba(0,0,0,0.2)'; tooltip.style.display='none'; tooltip.style.zIndex='1000'; shopWrapper.appendChild(tooltip); cartWidget.addEventListener('mouseenter',()=>{tooltip.style.display='block'; renderTooltip();}); cartWidget.addEventListener('mouseleave',()=>{tooltip.style.display='none';}); function renderTooltip(){ tooltip.innerHTML=''; if(cart.length===0){tooltip.textContent='Cart is empty'; return;} let sum=0; cart.forEach(item=>{ const line=document.createElement('div'); line.style.display='flex'; line.style.justifyContent='space-between'; line.style.marginBottom='4px'; line.textContent=`${item.name} (${item.version}) $${formatPrice(item.price)}`; tooltip.appendChild(line); sum+=item.price; }); const total=document.createElement('div'); total.style.fontWeight='bold'; total.style.textAlign='right'; total.textContent=`Total: $${formatPrice(sum)}`; tooltip.appendChild(total); } function updateCount(){countBubble.textContent=cart.length;} shopWrapper.appendChild(cartWidget); return { updateCount, renderTooltip }; } function renderShop(container,data){ container.innerHTML=''; container.style.position='relative'; const shopWrapper=document.createElement('div'); shopWrapper.className='widget-box'; shopWrapper.style.marginTop='10px'; const header=document.createElement('div'); header.className='widget-title'; header.innerHTML=`<span class="icon"><span class="he16-clan_desc"></span></span><h5>Shop</h5>`; shopWrapper.appendChild(header); const contentDiv=document.createElement('div'); contentDiv.className='widget-content padding'; contentDiv.style.position='relative'; shopWrapper.appendChild(contentDiv); const cartUI=createCartWidget(contentDiv); data.products.forEach(product=>{ const line=document.createElement('div'); line.style.display='flex'; line.style.alignItems='center'; line.style.marginTop='6px'; line.style.border='1px solid #ddd'; line.style.borderRadius='6px'; line.style.padding='8px'; const nameDiv=document.createElement('div'); nameDiv.textContent=product.name; nameDiv.style.flex='1'; line.appendChild(nameDiv); const versionSelect=document.createElement('select'); versionSelect.style.marginRight='10px'; let maxVer=Math.max(...product.versions.map(v=>parseFloat(v.name))); product.versions.forEach(v=>{ const opt=document.createElement('option'); opt.value=v.price; opt.textContent=v.name; if(parseFloat(v.name)===maxVer) opt.classList.add('rainbow-text'); versionSelect.appendChild(opt); }); line.appendChild(versionSelect); const priceSpan=document.createElement('span'); priceSpan.textContent='$'+formatPrice(product.versions[0]?.price||0); priceSpan.style.width='60px'; line.appendChild(priceSpan); versionSelect.addEventListener('change',()=>{ priceSpan.textContent='$'+formatPrice(parseFloat(versionSelect.value)); }); const addBtn=document.createElement('button'); addBtn.textContent='Add to Cart'; addBtn.style.marginLeft='10px'; addBtn.style.background='#5DADE2'; addBtn.style.color='white'; addBtn.style.border='none'; addBtn.style.borderRadius='4px'; addBtn.style.padding='6px 10px'; addBtn.style.cursor='pointer'; addBtn.addEventListener('click',()=>{ const selectedVer=versionSelect.options[versionSelect.selectedIndex].textContent; const selectedPrice=parseFloat(versionSelect.value); if(cart.some(item=>item.name===product.name&&item.version===selectedVer)) return alert('This version is already in the cart!'); cart.push({name:product.name,version:selectedVer,price:selectedPrice}); cartUI.updateCount(); cartUI.renderTooltip(); }); line.appendChild(addBtn); contentDiv.appendChild(line); }); const orderBtn=document.createElement('button'); orderBtn.textContent='Order Cart'; orderBtn.style.marginTop='12px'; orderBtn.style.background='#27ae60'; orderBtn.style.color='white'; orderBtn.style.border='none'; orderBtn.style.borderRadius='4px'; orderBtn.style.padding='6px 10px'; orderBtn.style.cursor='pointer'; orderBtn.addEventListener('click',async()=>{ if(!data.owner) return alert('No shop owner found'); if(cart.length===0) return alert('Cart empty!'); const userEl=document.querySelector('#user-nav .text'); const username=userEl?userEl.textContent.trim():'Unknown'; let body=`New Order from ${username}\nOrdered:\n`; cart.forEach(item=>{body+=`- ${item.name} (${item.version})\n`;}); try{ await fetch('/mail.php?action=new',{ method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded'}, body:new URLSearchParams({ action:'new', act:'new', to:data.owner, subject:'New Shop Order', text:body }) }); alert('Order sent!'); cart.length=0; cartUI.updateCount(); cartUI.renderTooltip(); }catch(e){alert('Failed to send order'); console.error(e);} }); contentDiv.appendChild(orderBtn); container.appendChild(shopWrapper); } const contentEl=findClanDescriptionElement(); if(!contentEl || contentEl.getAttribute(PROCESSED_ATTR)) return; contentEl.setAttribute(PROCESSED_ATTR,'1'); const parsed=parseDescription(contentEl.textContent); const descText=contentEl.textContent.replace(/(shopowner\s*:.*|software\s*:.*|- [^\(\n]+\([^)]+\))/gi,''); contentEl.innerHTML=processDescription(descText); const shopContainer=document.createElement('div'); contentEl.parentElement.appendChild(shopContainer); renderShop(shopContainer,parsed); })();