微件:GGLScratchGame
来自Limbo Wiki Mirror
点击灰色区域揭示内容,全部揭示后才能扫描。
剩余彩票:
<img class="ggl-bg"
src="
">
<button id="ggl-scan">扫描结果</button>
<style> .ggl-frame {
max-width: 420px; margin: 20px auto; padding: 10px; border: 2px solid #333; background: #111; color: #eee; font-family: sans-serif;
}
/* 顶部 */ .ggl-top {
position: absolute; top: 0; left: 0; width: 100%; height: 30%; padding: 10px; box-sizing: border-box;
}
.ggl-rules {
font-size: 14px; opacity: .8;
}
.ggl-remaining {
margin-top: 6px; font-size: 16px; font-weight: bold;
}
.ggl-tickets-left {
font-size: 14px; margin-top: 4px;
}
/* 彩票 */ .ggl-root {
position: relative; width: 100%; aspect-ratio: 1075 / 1911;
}
.ggl-bg {
width: 100%; display: block;
}
/* 刮奖区 */ .ggl-scratch-area {
position: absolute; left: 10%; top: 35%; width: 80%; height: 53%;
}
.ggl-grid {
display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(6, 1fr); gap: 4px; width: 100%; height: 100%;
}
/* 单格 */ .ggl-cell {
position: relative; cursor: pointer;
}
.ggl-cover, .ggl-reveal {
position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none;
}
.ggl-cover {
z-index: 3;
} .ggl-reveal {
z-index: 1;
}
/* 奖项层 */ .ggl-prize {
position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #000; text-align: center; pointer-events: none;
}
/* 吉祥物 & 气泡 */ .ggl-mascot {
position: absolute; left: 6%; top: 105%; bottom: 8%; font-size: 20px; color: #000;
}
.ggl-bubble {
position: absolute; left: 6%; bottom: 14%; top: 100%; width: 60%; background: rgba(255,255,255,.9); color: #000; padding: 6px; font-size: 13px;
}
/* 扫描 */ .ggl-controls {
position: absolute; right: 6%; bottom: 8%;
}
- ggl-scan {
opacity: .3;
}
- ggl-scan.active {
opacity: 1;
}
/* 遮罩 */ .ggl-overlay {
position: absolute; inset: 0; background: rgba(0,0,0,.9); z-index: 50; display: flex; align-items: center; justify-content: center;
}
.ggl-start-btn {
padding: 12px 24px; font-size: 16px;
} </style> <script> (function () {
/********************
* 全局状态
********************/
const gameState = {
totalTickets: 11,
currentTicket: 1,
totalCells: 30,
revealedCells: 0,
started: false,
data: 0
};
/********************
* DOM
********************/
const grid = document.querySelector('.ggl-grid');
const bubble = document.querySelector('.ggl-bubble');
const mascot = document.querySelector('.ggl-mascot');
const scanBtn = document.getElementById('ggl-scan');
const ticketLeftEl = document.getElementById('ggl-ticket-left');
const startMask = document.getElementById('ggl-start-mask');
mascot.style.color = '#000';
/********************
* 彩票剧情表(核心)
********************/
const TICKETS = {
1: {
mascot: '(^▽^)',
text: '欢迎,先来三张试试吧。',
rewards: ['DATA', 'EMPTY', 'EMPTY']
},
2: {
mascot: '(ノ◕ヮ◕)ノ',
text: '四个字可以连在一起。',
rewards: ['DATA','DATA','DATA','DATA']
},
3: {
mascot: '(・∀・)',
text: '中了刮刮乐!+1 Data',
rewards: ['DATA']
},
4: {
mascot: '(・_・)',
text: '什么都没中。',
rewards: []
},
5: {
mascot: '(;゚Д゚)',
text: '不对劲……又中了 Data。',
rewards: ['DATA']
},
6: {
mascot: ,
text: '什么都没有。',
rewards: []
},
7: {
mascot: '...',
text: '▒▓░▒▓░▒▓',
rewards: ['DATA']
},
8: {
mascot: '(^▽^)',
text: '中了两张 Data!',
rewards: ['DATA','DATA']
},
9: {
mascot: '(・_・)',
text: '……全部都是 Data?',
rewards: Array(30).fill('DATA')
},
10: {
mascot: '(;゚Д゚)',
text: '停下来。',
rewards: [],
lock: true
},
11: {
mascot: '平安喜乐',
text: '你知道的太多了。',
rewards: [],
end: true
}
};
/********************
* 奖项坐标生成
********************/
function buildRewardMap(ticket) {
const map = Array(30).fill('EMPTY');
const rewards = TICKETS[ticket].rewards || [];
rewards.forEach((r, i) => map[i] = r);
return map;
}
/********************
* UI 刷新
********************/
function updateTopUI() {
if (!ticketLeftEl) return;
ticketLeftEl.textContent =
gameState.totalTickets - gameState.currentTicket + 1;
}
function updateMascot(ticket) {
mascot.textContent = TICKETS[ticket].mascot || ;
bubble.textContent = TICKETS[ticket].text || ;
}
/********************
* 构建 30 格
********************/
function buildGrid(ticket) {
grid.innerHTML = ;
gameState.revealedCells = 0;
scanBtn.classList.remove('active');
const rewardMap = buildRewardMap(ticket); const locked = TICKETS[ticket].lock;
for (let i = 0; i < 30; i++) {
const cell = document.createElement('div');
cell.className = 'ggl-cell';
cell.innerHTML = `
<img src="
">
${rewardMap[i] === 'DATA' ? 'DATA' : }
`;
const cover = cell.querySelector('.ggl-cover');
if (!locked) {
cover.addEventListener('click', () => {
if (cell.dataset.done) return;
cell.dataset.done = '1';
cover.style.opacity = '0';
gameState.revealedCells++;
if (rewardMap[i] === 'DATA') {
gameState.data++;
}
if (gameState.revealedCells >= gameState.totalCells) {
scanBtn.classList.add('active');
bubble.textContent = '可以扫描了。';
}
});
}
grid.appendChild(cell); } }
/********************
* 下一张彩票
********************/
function nextTicket() {
gameState.currentTicket++;
updateTopUI();
if (gameState.currentTicket > gameState.totalTickets) return;
if (gameState.currentTicket === 11) {
document.body.style.filter = 'invert(1)';
bubble.style.background = '#000';
bubble.style.color = 'red';
}
updateMascot(gameState.currentTicket); buildGrid(gameState.currentTicket); }
/********************
* 扫描按钮
********************/
scanBtn.addEventListener('click', () => {
if (!scanBtn.classList.contains('active')) return;
bubble.textContent = '扫描中……';
setTimeout(() => {
if (TICKETS[gameState.currentTicket].end) {
location.href = '/index.php?title=六世恶言之一';
} else {
nextTicket();
}
}, 800);
});
/********************
* 初始化遮罩
********************/
if (startMask) {
startMask.addEventListener('click', () => {
startMask.remove();
gameState.started = true;
updateTopUI();
updateMascot(1);
buildGrid(1);
});
} else {
updateTopUI();
updateMascot(1);
buildGrid(1);
}
})(); </script>
