QuickBuy panel with hide/show toggle, remembered collapse, full working cross-page quick buy (fixed search after moving to marketplace)
目前為
// ==UserScript==
// @name Dead Frontier - QuickBuy Toolbar + Collapse + Remember State + Fancy (Fixed Search)
// @namespace Zega
// @version 1.39
// @description QuickBuy panel with hide/show toggle, remembered collapse, full working cross-page quick buy (fixed search after moving to marketplace)
// @match https://fairview.deadfrontier.com/onlinezombiemmo/index.php*
// @grant none
// ==/UserScript==
(function() {
'use strict';
window.BrowserImplant_QuickBuy = true;
const highlightConfig = JSON.parse(localStorage.getItem('qb_highlightConfig') || '{}');
const foodMedItems = [
{ label: 'Buy 1 Whiskey', search: 'Whiskey', qty: 1 },
{ label: 'Buy 2 Whiskey', search: 'Whiskey', qty: 2 },
{ label: 'Buy 1 Nerotonin 8B', search: 'Nerotonin 8B', qty: 1 },
{ label: 'Buy 2 Nerotonin 8B', search: 'Nerotonin 8B', qty: 2 },
{ label: 'Buy Energy Bar', search: 'Energy Bar', qty: 1 },
{ label: 'Buy Repair Kit', search: 'Repair Kit', qty: 1 }
];
const ammoItems = [
{ label: '14mm Stack of Ammo (1200)', search: '14mm Rifle Bullets', qty: 1200 },
{ label: '12.7mm Stack of Ammo (1200)', search: '12.7mm Rifle Bullets', qty: 1200 },
{ label: '9mm Rifle Stack of Ammo (1200)', search: '9mm Rifle Bullets', qty: 1200 },
{ label: '.55 Handgun Stack of Ammo (1600)', search: '.55 Handgun Bullets', qty: 1600 },
{ label: 'Biomass Stack of Ammo (1000)', search: 'Biomass', qty: 1000 },
{ label: 'Energy Cell Stack of Ammo (1600)', search: 'Energy Cell', qty: 1600 },
{ label: 'Grenade Stack of Ammo (400)', search: 'Grenades', qty: 400 },
{ label: 'Heavy Grenade Stack of Ammo (400)', search: 'Heavy Grenades', qty: 400 },
{ label: 'Gasoline Stack of Ammo (4546)', search: 'Gasoline', qty: 4546 },
{ label: '10 Gauge Stack of Ammo (800)', search: '10 Gauge Shells', qty: 800 },
{ label: '12 Gauge Stack of Ammo (800)', search: '12 Gauge Shells', qty: 800 },
{ label: '16 Gauge Stack of Ammo (800)', search: '16 Gauge Shells', qty: 800 },
{ label: '20 Gauge Stack of Ammo (800)', search: '20 Gauge Shells', qty: 800 }
];
function createQuickBuyToolbar() {
const rightTd = document.querySelector("td.design2010[style*='right_margin.jpg']");
if (!rightTd) return console.warn('QuickBuy: right-margin cell not found');
rightTd.style.position = 'relative';
const fieldset = document.createElement('fieldset');
fieldset.id = 'quickbuy-fieldset';
Object.assign(fieldset.style, {
position: 'absolute', top: '120px', left: '10px',
width: '420px', border: '1px solid #666',
padding: '8px 12px', background: 'rgba(0,0,0,0.35)',
borderRadius: '8px', boxShadow: '0 4px 12px rgba(0,0,0,0.6)',
zIndex: '10000'
});
const legend = document.createElement('legend');
legend.innerHTML = `<span style="color:#ffd700;">QuickBuys</span> <button id="collapse-quickbuy" style="background:none;border:none;color:#ffd700;font-size:16px;cursor:pointer;">[–]</button>`;
Object.assign(legend.style, { padding: '0 6px', fontSize: '13px' });
fieldset.appendChild(legend);
const container = document.createElement('div');
container.id = 'quickbuy-container';
fieldset.appendChild(container);
rightTd.appendChild(fieldset);
appendSection(container, 'Food / Medical', foodMedItems);
container.appendChild(Object.assign(document.createElement('hr'), {
style: 'border:0;border-top:1px solid #666;margin:8px 0;'
}));
appendSection(container, 'Ammo', ammoItems);
const collapseBtn = document.getElementById('collapse-quickbuy');
if (localStorage.getItem('quickbuyCollapsed') === 'true') {
container.style.display = 'none';
collapseBtn.textContent = '[+]';
}
collapseBtn.addEventListener('click', () => {
if (container.style.display === 'none') {
container.style.display = 'block';
collapseBtn.textContent = '[–]';
localStorage.setItem('quickbuyCollapsed', 'false');
} else {
container.style.display = 'none';
collapseBtn.textContent = '[+]';
localStorage.setItem('quickbuyCollapsed', 'true');
}
});
}
function appendSection(container, title, items) {
const label = document.createElement('div');
label.textContent = title;
Object.assign(label.style, {
color: 'gold', fontWeight: 'bold',
margin: title === 'Ammo' ? '2px 0 4px' : '4px 0 2px'
});
container.appendChild(label);
const grid = document.createElement('div');
Object.assign(grid.style, {
display: 'grid', gridTemplateColumns: 'repeat(2,200px)', gap: '8px'
});
items.forEach(item => grid.appendChild(createButton(item)));
container.appendChild(grid);
}
function createButton(item) {
const btn = document.createElement('button');
btn.textContent = item.label;
Object.assign(btn.style, {
width: '200px', height: '32px',
backgroundColor: highlightConfig[item.search]?.backgroundColor || '#222',
color: highlightConfig[item.search]?.color || 'gold',
border: '2px solid #555', borderRadius: '8px',
cursor: 'pointer', textAlign: 'center'
});
btn.addEventListener('contextmenu', e => {
e.preventDefault();
const key = item.search;
if (highlightConfig[key]?.backgroundColor === 'green') {
delete highlightConfig[key];
btn.style.backgroundColor = '#222';
btn.style.color = 'gold';
} else {
highlightConfig[key] = { backgroundColor: 'green', color: 'black' };
btn.style.backgroundColor = 'green';
btn.style.color = 'black';
}
localStorage.setItem('qb_highlightConfig', JSON.stringify(highlightConfig));
});
btn.addEventListener('click', () => quickBuy(item.search, item.qty));
return btn;
}
function quickBuy(searchTerm, qty) {
sessionStorage.setItem('quickBuy_pending', JSON.stringify({ term: searchTerm, qty }));
window.location.href = `${location.origin}${location.pathname}?page=35`;
}
function realClick(el) {
el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
}
function waitAndPurchase(searchTerm, qty) {
const obs = new MutationObserver((_, observer) => {
const selector = `div.fakeItem[data-quantity="${qty}"]`;
const items = Array.from(document.querySelectorAll(selector))
.filter(div => div.querySelector('.itemName')?.textContent.trim() === searchTerm);
if (items.length) {
observer.disconnect();
purchaseItem(items[0]);
}
});
obs.observe(document.body, { childList: true, subtree: true });
}
function purchaseItem(div) {
const buyBtn = div.querySelector('button[data-action="buyItem"]');
if (buyBtn) {
realClick(buyBtn);
waitForYesClick();
}
}
function waitForYesClick() {
const start = Date.now();
(function poll() {
const yes = Array.from(document.querySelectorAll('button'))
.find(b => b.innerText.trim().toLowerCase() === 'yes');
if (yes) realClick(yes);
else if (Date.now() - start < 5000) setTimeout(poll, 100);
})();
}
window.addEventListener('load', () => {
setTimeout(createQuickBuyToolbar, 500);
// After load, check if there was a pending QuickBuy action
const pending = sessionStorage.getItem('quickBuy_pending');
if (pending && window.location.search.includes('page=35')) {
const { term, qty } = JSON.parse(pending);
sessionStorage.removeItem('quickBuy_pending');
const input = document.querySelector('#searchField');
const mk = document.querySelector('#makeSearch');
if (input && mk) {
input.value = term;
realClick(mk);
waitAndPurchase(term, qty);
}
}
});
})();