|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
|
|
|
const lootTrack = document.getElementById('lootTrack'); |
|
|
const lootWrapper = document.getElementById('lootWrapper'); |
|
|
const multiTrack = document.getElementById('multiTrack'); |
|
|
const multiWrapper = document.getElementById('multiWrapper'); |
|
|
const spinBtn = document.getElementById('spinBtn'); |
|
|
const popupBackdrop = document.getElementById('popupBackdrop'); |
|
|
const popupTotal = document.getElementById('popupTotal'); |
|
|
const popupBase = document.getElementById('popupBase'); |
|
|
const popupMulti = document.getElementById('popupMulti'); |
|
|
const popupClose = document.getElementById('popupClose'); |
|
|
|
|
|
|
|
|
const lootBoxesData = [ |
|
|
{ prize: 10, rarity: 'green' }, |
|
|
{ prize: 15, rarity: 'blue' }, |
|
|
{ prize: 20, rarity: 'blue' }, |
|
|
{ prize: 25, rarity: 'green' }, |
|
|
{ prize: 30, rarity: 'purple' }, |
|
|
{ prize: 35, rarity: 'purple' }, |
|
|
{ prize: 40, rarity: 'green' }, |
|
|
{ prize: 45, rarity: 'blue' }, |
|
|
{ prize: 50, rarity: 'purple' }, |
|
|
{ prize: 100, rarity: 'gold' } |
|
|
]; |
|
|
|
|
|
|
|
|
const multipliers = [1, 1.25, 1.5, 2, 3, 5, 1, 1.25, 1.5, 2, 3, 5]; |
|
|
|
|
|
|
|
|
function initializeTracks() { |
|
|
|
|
|
lootBoxesData.forEach(box => { |
|
|
const boxElement = document.createElement('div'); |
|
|
boxElement.className = 'loot-box'; |
|
|
boxElement.dataset.prize = box.prize; |
|
|
boxElement.dataset.rarity = box.rarity; |
|
|
|
|
|
const inner = document.createElement('div'); |
|
|
inner.className = 'loot-box-inner'; |
|
|
boxElement.appendChild(inner); |
|
|
|
|
|
lootTrack.appendChild(boxElement); |
|
|
}); |
|
|
|
|
|
|
|
|
multipliers.forEach(m => { |
|
|
const pill = document.createElement('div'); |
|
|
pill.className = 'multi-pill'; |
|
|
pill.dataset.m = m; |
|
|
pill.textContent = `×${m}`; |
|
|
multiTrack.appendChild(pill); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
async function spinTrack(track, items, wrapper, extraMinSteps, extraMaxSteps, duration) { |
|
|
return new Promise(resolve => { |
|
|
|
|
|
items.forEach(el => { |
|
|
el.classList.remove('selected', 'motion-blur'); |
|
|
}); |
|
|
|
|
|
const targetIndex = Math.floor(Math.random() * items.length); |
|
|
const wrapperRect = wrapper.getBoundingClientRect(); |
|
|
const centerX = wrapperRect.left + wrapperRect.width / 2; |
|
|
const targetRect = items[targetIndex].getBoundingClientRect(); |
|
|
const targetCenter = targetRect.left + targetRect.width / 2; |
|
|
const deltaToCenter = centerX - targetCenter; |
|
|
|
|
|
|
|
|
let step = 0; |
|
|
if (items.length > 1) { |
|
|
const r0 = items[0].getBoundingClientRect(); |
|
|
const r1 = items[1].getBoundingClientRect(); |
|
|
step = Math.abs((r1.left + r1.width / 2) - (r0.left + r0.width / 2)); |
|
|
} else { |
|
|
step = targetRect.width + 18; |
|
|
} |
|
|
|
|
|
const extraSteps = extraMinSteps + Math.floor(Math.random() * (extraMaxSteps - extraMinSteps + 1)); |
|
|
const direction = Math.random() > 0.5 ? 1 : -1; |
|
|
const extraDistance = extraSteps * step * direction; |
|
|
const currentTranslate = parseFloat(track.style.transform?.replace('translateX(', '').replace('px)', '') || '0'); |
|
|
const finalTranslate = currentTranslate + deltaToCenter + extraDistance; |
|
|
|
|
|
|
|
|
items.forEach((el, i) => { |
|
|
if (i !== targetIndex) el.classList.add('motion-blur'); |
|
|
}); |
|
|
|
|
|
|
|
|
track.style.transition = `transform ${duration}ms cubic-bezier(0.1, 0.9, 0.24, 1)`; |
|
|
track.style.transform = `translateX(${finalTranslate}px)`; |
|
|
|
|
|
setTimeout(() => { |
|
|
track.style.transition = ''; |
|
|
items.forEach(el => el.classList.remove('motion-blur')); |
|
|
items[targetIndex].classList.add('selected'); |
|
|
resolve({ index: targetIndex, element: items[targetIndex] }); |
|
|
}, duration + 40); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
async function handleSpin() { |
|
|
if (spinBtn.disabled) return; |
|
|
spinBtn.disabled = true; |
|
|
|
|
|
|
|
|
const lootResult = await spinTrack(lootTrack, [...lootTrack.children], lootWrapper, 3, 6, 1100); |
|
|
const basePrize = parseFloat(lootResult.element.dataset.prize); |
|
|
|
|
|
|
|
|
const multiResult = await spinTrack(multiTrack, [...multiTrack.children], multiWrapper, 4, 7, 1000); |
|
|
const multiplier = parseFloat(multiResult.element.dataset.m); |
|
|
|
|
|
|
|
|
const total = Math.round(basePrize * multiplier * 100) / 100; |
|
|
|
|
|
|
|
|
popupTotal.textContent = `${total} SC`; |
|
|
popupBase.textContent = `Base: ${basePrize} SC`; |
|
|
popupMulti.textContent = `Multiplier: ×${multiplier}`; |
|
|
popupBackdrop.classList.remove('hidden'); |
|
|
|
|
|
spinBtn.disabled = false; |
|
|
} |
|
|
|
|
|
|
|
|
spinBtn.addEventListener('click', handleSpin); |
|
|
popupClose.addEventListener('click', () => { |
|
|
popupBackdrop.classList.add('hidden'); |
|
|
}); |
|
|
popupBackdrop.addEventListener('click', (e) => { |
|
|
if (e.target === popupBackdrop) { |
|
|
popupBackdrop.classList.add('hidden'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
initializeTracks(); |
|
|
}); |