微件:Test:修订间差异
无编辑摘要 标签:(旧)WikiEditor |
无编辑摘要 标签:(旧)WikiEditor |
||
| (未显示同一用户的6个中间版本) | |||
| 第11行: | 第11行: | ||
刮开奖券 · 在整张刮完后交由bot扫描<br> | 刮开奖券 · 在整张刮完后交由bot扫描<br> | ||
刮出数字即能获得对应额度的data<br> | 刮出数字即能获得对应额度的data<br> | ||
当“平”“安”“喜”“乐”四个字连城一条线时,可再获得一张彩票<br> | |||
看不懂也没关系!bot会告诉你结果! | 看不懂也没关系!bot会告诉你结果! | ||
</div> | </div> | ||
| 第44行: | 第44行: | ||
<style> | <style> | ||
.ggl-root{width:375px;margin:auto;font-family:sans-serif;position:relative} | .ggl-root{width:375px;margin:auto;font-family:sans-serif;position:relative} | ||
.ggl-mask{position:absolute;inset:0;background:#000d;z-index:99;display:flex;align-items:center;justify-content:center} | .ggl-mask{position:absolute;inset:0;background:#000d;z-index:99;display:flex;align-items:center;justify-content:center} | ||
| 第76行: | 第75行: | ||
.ggl-redeem-hit{ | .ggl-redeem-hit{ | ||
position:absolute;bottom:1%;left:2%; | position:absolute; | ||
width:48%;height:10%; | bottom:1%; | ||
background:transparent;border:none | left:2%; | ||
width:48%; | |||
height:10%; | |||
background:transparent; | |||
border:none; | |||
cursor:pointer; | |||
} | } | ||
#ggl-ending-container{ | #ggl-ending-container{ | ||
max-width:800px; | max-width:800px; | ||
| 第93行: | 第96行: | ||
} | } | ||
.mw-collapsible{overflow:hidden} | .mw-collapsible{overflow:hidden} | ||
.wikitable{border-collapse:collapse;width:100%} | .wikitable{border-collapse:collapse;width:100%} | ||
.wikitable th, .wikitable td{border:1px solid #aaa;padding:6px} | .wikitable th, .wikitable td{border:1px solid #aaa;padding:6px} | ||
.poem{white-space:pre-wrap;font-family:serif;background:#f8f8f8;padding:8px;border-left:3px solid #ddd} | .poem{white-space:pre-wrap;font-family:serif;background:#f8f8f8;padding:8px;border-left:3px solid #ddd} | ||
</style> | </style> | ||
| 第105行: | 第106行: | ||
(function(){ | (function(){ | ||
const root = document.querySelector('.ggl-root'); | const root = document.querySelector('.ggl-root'); | ||
const grid = document.querySelector('.ggl-grid'); | const grid = document.querySelector('.ggl-grid'); | ||
| 第125行: | 第125行: | ||
let redeemLocked = false; | let redeemLocked = false; | ||
const | /* ===== 彩票数组(保留文档二的规范结构) ===== */ | ||
const lotteryList = [ | |||
/* 1 */ | |||
{ | |||
left: 2, | |||
data: 0, | |||
mascot: '|ω`)', | |||
bubble: '你好呀,俺是负责播报结果的。刮奖阶段不用在意我。', | |||
onScan: '哇!中了25MB耶,回本了回本了。', | |||
onRedeem: '兑奖文本占位 1', | |||
rewards: { | |||
0:'畅',1:'舒',2:'遂',3:'顺',4:'达',5:'欢',6:'5',7:'欣',8:'怡',9:'和', | |||
10:'睦',11:'融',12:'洽',13:'美',14:'善',15:'吉',16:'昌',17:'20', | |||
18:'兴',19:'平',20:'安',21:'喜',22:'乐',23:'平',24:'安', | |||
25:'盛',26:'喜',27:'乐',28:'悦',29:'睦' | |||
} | |||
}, | |||
/* 2 */ | |||
{ | |||
left: 1, | |||
data: 25, | |||
mascot: '|∀`)ノ', | |||
bubble: '虽然好像彩票上下都没标,但是中奖金额的单位默认是MB哦~', | |||
onScan: '1MB,然后是……bingo!不对,“平安喜乐”!第二行,横着和斜着,两组!这就去给你加上!', | |||
onRedeem: '兑奖文本占位 2', | |||
rewards: { | |||
0:'遂',1:'舒',2:'达',3:'顺',4:'畅',5:'平',6:'安',7:'喜',8:'乐',9:'和', | |||
10:'睦',11:'安',12:'1',13:'美',14:'善',15:'吉',16:'昌',17:'喜', | |||
18:'盛',19:'兴',20:'欢',21:'平',22:'悦',23:'乐',24:'欣', | |||
25:'怡',26:'洽',27:'融',28:'欢',29:'怡' | |||
} | |||
}, | |||
/* 3 */ | |||
{ | |||
left: 2, | |||
data: 26, | |||
mascot: '|o`)', | |||
bubble: '耶咦耶咦耶咦耶奥🎶我们又能多相处一会儿了!', | |||
onScan: '让我看看,36MB,外加一张彩票!<br>【这么好中,真的假的?都不用我……】', | |||
onRedeem: '兑奖文本占位 3', | |||
rewards: { | |||
0:'舒',1:'平',2:'场',3:'遂',4:'15',5:'欢',6:'安',7:'悦',8:'欣',9:'怡', | |||
10:'和',11:'喜',12:'睦',13:'融',14:'20',15:'洽',16:'美',17:'乐', | |||
18:'善',19:'吉',20:'昌',21:'盛',22:'兴',23:'16', | |||
24:'顺',25:'平',26:'安',27:'喜',28:'乐',29:'达' | |||
} | |||
}, | |||
/* 4 */ | |||
{ | |||
left: 2, | |||
data: 62, | |||
mascot: '|д`)', | |||
bubble: '*紧急寻找说明书中*', | |||
onScan: '扫描完成:null。终于正常了嘛……<br>嘿嘿,果然还需要我来帮一把!', | |||
onRedeem: '兑奖文本占位 4', | |||
rewards: { | |||
0:'欣',1:'平',2:'怡',3:'畅',4:'舒',5:'安',6:'遂',7:'盛',8:'顺',9:'达', | |||
10:'和',11:'睦',12:'融',13:'喜',14:'洽',15:'美',16:'善',17:'吉', | |||
18:'昌',19:'乐',20:'兴',21:'欢',22:'平',23:'安',24:'悦', | |||
25:'喜',26:'乐',27:'融',28:'洽',29:'兴' | |||
} | |||
}, | |||
/* 5 */ | |||
{ | |||
left: 2, | |||
data: 62, | |||
mascot: '|_・)', | |||
bubble: '什么都没有<br>【我该干点什么,还是说些什么?<br>那边的运气不会一直好下去,死脑子,快想啊呜呜……】', | |||
onScan: '哦哦,扫描完成!10MB!<br>【完了完了,这下剩一张了,我得再……】', | |||
onRedeem: '兑奖文本占位 5', | |||
rewards: { | |||
0:'欣',1:'平',2:'怡',3:'1',4:'舒',5:'安',6:'遂',7:'喜',8:'顺',9:'2', | |||
10:'和',11:'1',12:'融',13:'乐',14:'洽',15:'美',16:'善',17:'吉', | |||
18:'5',19:'昌',20:'盛',21:'兴',22:'欢',23:'悦',24:'1', | |||
25:'平',26:'乐',27:'畅',28:'达',29:'喜' | |||
} | |||
}, | |||
/* 6 */ | |||
{ | |||
left: 1, | |||
data: 72, | |||
mascot: '|??)', | |||
bubble: '不不不,我不是通过修改多添了一张票吗?为什么还是结束了?<br>我这是……我在……<br>不……不要……不要!!!', | |||
onScan: 'A̜̤̓b̦̅́ǒ̮̚r̛̰̪t̗̗͂:̵̂̚ ů̡̘̪̿̎ñ̸̯̻͈̤͊r͍̥̜̾̂̃̀è̡̧̖̬̲̏s͏̴̮̬̬̳͋o̶̡̬̖̖͌̈l̵̴̪̻̄̚͏v̤̭͉̋̂̽̑a̧̩̫͈̦̔̅b̢̮̘̼̥̐̏l̢̟̳̈́͊̊̀ȩ̧͎̩͌̕ s̱̭̙i̥̘͆t̡̥̔ũ̞̠̗a̸̡̺̕t̫i̝̠̾o̺͉͂ǹ̲̎。', | |||
onRedeem: '兑奖文本占位 6', | |||
rewards: { | |||
0:'6',1:'顺',2:'6',3:'遂',4:'6',5:'6',6:'6',7:'6',8:'6',9:'6', | |||
10:'平',11:'6',12:'6',13:'6',14:'和',15:'平',16:'6',17:'6', | |||
18:'6',19:'和',20:'安',21:'6',22:'6',23:'6',24:'睦', | |||
25:'安',26:'6',27:'6',28:'6',29:'睦' | |||
} | |||
}, | |||
/* 7 */ | |||
{ | |||
left: 0, | |||
data: '▒▓', | |||
mascot: '|V̵̨̄I̤)', | |||
bubble: '<br>……<br>', | |||
onScan: '扫描完成:无数据。', | |||
onRedeem: '兑奖文本占位 7', | |||
rewards: { | |||
0:'和',1:'睦',2:'融',3:'洽',4:'美',5:'善',6:'吉',7:'昌',8:'盛',9:'兴', | |||
10:'欢',11:'平',12:'悦',13:'顺',14:'欣',15:'怡',16:'安',17:'畅', | |||
18:'乐',19:'舒',20:'遂',21:'喜',22:'达',23:'平',24:'安', | |||
25:'喜',26:'乐',27:'欢',28:'悦',29:'欣' | |||
} | |||
}, | |||
/* 8 */ | |||
{ | |||
left: 0, | |||
data: '在此输入数字', | |||
mascot: '|̡̔̿̆∀̯̠̥̒◕̪͇̻̈́)̤͆̾͊', | |||
bubble: '没素质啊,干嘛挠人痒痒肉', | |||
onScan: '就你还想使唤我?', | |||
onRedeem: '兑奖文本占位 8', | |||
rewards: { | |||
0:'美',1:'善',2:'吉',3:'昌',4:'盛',5:'兴',6:'平',7:'欢',8:'悦',9:'欣', | |||
10:'平',11:'安',12:'喜',13:'乐',14:'89',15:'畅',16:'喜',17:'32', | |||
18:'遂',19:'顺',20:'达',21:'乐',22:'睦',23:'融',24:'怡', | |||
25:'安',26:'和',27:'舒',28:'200',29:'洽' | |||
} | |||
}, | |||
/* 9 */ | |||
{ | |||
left: 1, | |||
data: '—', | |||
mascot: '|?̷̊̇?̶̨̦)', | |||
bubble: '恭恭恭恭喜喜喜喜中中中中奖奖奖奖', | |||
onScan: '3̘͉̌9̥͂̊3̒̂́4̖̜̾1̻̋̉8̿̊́1̼̓̅3̼̏̋8͍͍̍3̴͍̏5̸̆́3̴̠̉3̂̽̆ +̷̰ͅ 7̺͉̒9̢̰̔3̬̆̓4̶̦̬1̧̧̧6̛͍̘…͉̥̄…̜̱̕', | |||
onRedeem: '兑奖文本占位 9', | |||
rewards: { | |||
0:'17 Byte',1:'89 KB',2:'1023 MB',3:'457 GB',4:'781 bit', | |||
5:'902 TB',6:'314 Byte',7:'567 KB',8:'890 MB',9:'10 GB', | |||
10:'21 bit',11:'144 TB',12:'169 Byte',13:'196 KB',14:'225 MB', | |||
15:'256 GB',16:'289 bit',17:'3 Byte',18:'361 KB',19:'400 TB', | |||
20:'41 MB',21:'484 GB',22:'529 bit',23:'576 Byte',24:'625 KB', | |||
25:'676 TB',26:'729 MB',27:'84 GB',28:'841 bit',29:'900 Byte' | |||
} | |||
}, | |||
/* 10 */ | |||
{ | |||
left: 0, | |||
data: 'ERROR!', | |||
mascot: '|̴̢͌ω̗̦̐`͍̀̈́)̘̗̾', | |||
bubble: 'Oh! Ý̦ȯ͇u̪͆ l̫̒o̙̘o̠͂k̮͂ s̩̹ö̧ f̧͈a̤͋m̮͏i̟̐l̂̀i̳͆a̯ȑ̉...', | |||
onScan: '警告:DATA 溢出。', | |||
onRedeem: '兑奖文本占位 10', | |||
rewards: { | |||
0:'D̸A̍T̴A̵',1:'D͊ẠT̿A̘',2:'D̐A̬T̰A̢',3:'D̶ÃT̚À',4:'D̜ǍT̘A͆',5:'D̝͏A̸̛T̞̩A͇̒',6:'D̵́A̵̗T̈̀Ȃ̐',7:'D̢̫A̬̾Ţ̏Ą̘',8:'D͇̉A̓̔T̜̿A̷̯',9:'D̦̽̂À͈͌T͍̟̋Å̟͇',10:'D̢͍ͅA̶̹̝Ṱ̑̏A̵̯̱',11:'D̠̖͆Â̛̲T̸̿̃Å̝̖',12:'Ḏ̨͍À̆̅T̫͂̐Ȧ̷̺',13:'D̮̱̽͆Ǎ̡̯̦Ț̡̓́À̝̹͋',14:'D̮̤̣͌Á̷̃́T̟̀̀͂Ả̷̺̂',15:'D̼̪̜̈A̷̮͍͆T̵̢̹̏A̩̪̹̦',16:'D̶̰̠̅́A͂̎̇̉̔T̨̡͈̃̅A̰͌͋̈́̑',17:'D̨̯̝̑̋A̫̱̋̐̅T̞̎͊̅̄A̦̳̣̿̚',18:'D̨̨̞̙̆À̟̻̌̓Ṱ̥̉̄ͅA̧̼̣̫͂',19:'D̖͏̯̃̽̃A̷͉̎̿̾̿T̊̀͏̺̩̘Á̟̲̦̿̔',20:'Ḑ̫̞̿̈̈́A̶̛̬͇̿͂T̨̬̦̺̀̉Á̗̠̋͂̃',21:'D̡̧̛̫̼̓A̛̅̂̊̑̽T̸̛̞͎̓̂Ȧ̠̟̪̑̀',22:'D̡̻͉̹̽̇͌Á͈̥̥́̈́̌T̪̮̍̒̏̎̚A̷̦͇̩̰͆͆',23:'D̸͇̠͍͍̓̈A͎̭̹̮͆͌́T̤̱̖̉̉̉̀A̺̬̤̺̯̚ͅ',24:'D̶̬̱̥̠̊̆A̴̪̙̜̽̆͊T̤͏̖̪̈́͌̃A̪̮̞̪̰͋͆',25:'D̴̢̼̗̝̊̋A̸̸̟͎̅̓̃T͇͈̗͇̱̓̐Ȁ̸̎̎̉̇́',26:'D̷̴̸̛̳̦͆Ǎ̷̳̤̱̯̄Ṫ̶̢̼͋̌̾A̡̢͍̮̓̆̚',27:'D̸̴̛̘̭̖̓A̵̡̢͉̫̒̓T̨̼̼̑̓͊̒Ä̦̪́̒̆̀̕',28:'Ḏ̸̨͊̍̍̎̍À̧͉̠̺̻͍̐T̷̡̤̳͊̃̓͆Â̢̟̤̹̯̅ͅ',29:'D̮̲̪̲̅́̊͌̾̎Ạ̧̤̩̥̦̒̂͊͏T̼̳̲̭̖̺̆́̀͏Â̴̢͎͍͈̥̾̾̀' | |||
} | |||
}, | |||
/* 11 */ | |||
{ | |||
left: '?̜̻̤̹́̂̈́̑̀?', | |||
data: 'ÈRROR', | |||
mascot: 'Ĕ̴̢̟̑ñ̡̬̑̽d̝̑͋', | |||
bubble: '你知道的太多了。', | |||
onScan: '权限越界。<br>祝您平安喜乐。', | |||
onRedeem: '兑奖文本占位 11', | |||
rewards: { | |||
0:'平',1:'安',2:'安',3:'平',4:'喜',5:'喜',6:'乐',7:'喜',8:'安',9:'平', | |||
10:'安',11:'平',12:'安',13:'喜',14:'乐',15:'乐',16:'喜',17:'平', | |||
18:'安',19:'安',20:'喜',21:'平',22:'乐',23:'乐',24:'平', | |||
25:'平',26:'安',27:'安',28:'喜',29:'乐' | |||
} | |||
} | |||
]; | ]; | ||
/* 兼容别名(便于使用文档一中的代码片段) */ | |||
const TICKETS = lotteryList; | |||
/* ===== 动画:淡出遮罩层(替代直接 display:none) ===== */ | |||
function fadeOutCover(cover, done){ | function fadeOutCover(cover, done){ | ||
const start = performance.now(); | const start = performance.now(); | ||
| 第156行: | 第324行: | ||
} | } | ||
/* ===== 构建票面格子 ===== */ | |||
function build(){ | function build(){ | ||
if(finalized) return; | if(finalized) return; | ||
| 第166行: | 第335行: | ||
dataEl.textContent = t.data; | dataEl.textContent = t.data; | ||
mascot.textContent = t.mascot || ''; | mascot.textContent = t.mascot || ''; | ||
// 使用 innerHTML 以支持票据内的简单 HTML(如换行) | |||
setBubbleHtml(t.bubble || ''); | |||
scan.textContent = '扫描结果'; | scan.textContent = '扫描结果'; | ||
| 第191行: | 第361行: | ||
grid.appendChild(c); | grid.appendChild(c); | ||
} | } | ||
updateMascotPosition(); | |||
} | } | ||
/* ===== 无限警告(用于特定票面触发) ===== */ | |||
function startInfiniteAlert(){ | function startInfiniteAlert(){ | ||
if(alertTimer) return; | if(alertTimer) return; | ||
const TEXT = ' | const TEXT = '哎呀,崩溃啦!<br>显示该词条时出现错误,要继续浏览,请尝试刷新或转到其他页面。<br>如果您频繁遇到此问题,请尝试以上建议。'; | ||
(function loop(){ | (function loop(){ | ||
alert(TEXT); | alert(TEXT); | ||
| 第202行: | 第374行: | ||
} | } | ||
/* ===== 兑奖模态(保留文档一的交互:覆盖层、延迟、再给一张票等) ===== */ | |||
function showRedeemModal(){ | function showRedeemModal(){ | ||
if(redeemLocked) return; | if(redeemLocked) return; | ||
| 第225行: | 第398行: | ||
font-size:14px; | font-size:14px; | ||
`; | `; | ||
box.textContent = ' | box.textContent = '兑奖区遭到损坏,无法兑奖'; | ||
overlay.appendChild(box); | overlay.appendChild(box); | ||
| 第233行: | 第406行: | ||
box.innerHTML = ` | box.innerHTML = ` | ||
<div>系统已记录</div> | <div>系统已记录</div> | ||
<div> | <div>考虑为初犯,不排除无处可能,将补充一张彩票</div> | ||
`; | `; | ||
const btn = document.createElement('button'); | const btn = document.createElement('button'); | ||
| 第248行: | 第421行: | ||
} | } | ||
/* ===== 内置 | /* ===== 表情位置动态调整 ===== */ | ||
function updateMascotPosition(){ | |||
if(!mascot || !bubble) return; | |||
const ticket = document.querySelector('.ggl-ticket'); | |||
if(!ticket) return; | |||
const bubbleTop = bubble.offsetTop || 0; | |||
const bubbleHeight = bubble.offsetHeight || 0; | |||
const gap = 6; // px | |||
const newTop = bubbleTop + bubbleHeight + gap; | |||
mascot.style.top = newTop + 'px'; | |||
} | |||
// 窗口改变时重新计算位置(防抖) | |||
window.addEventListener('resize', ()=>{ | |||
clearTimeout(window.__ggl_resize_timeout); | |||
window.__ggl_resize_timeout = setTimeout(updateMascotPosition, 80); | |||
}); | |||
// 监听气泡内容变化,自动调整表情位置 | |||
try{ | |||
const bubbleEl = document.querySelector('.ggl-bubble'); | |||
if(bubbleEl){ | |||
const bubbleObserver = new MutationObserver(()=>{ | |||
updateMascotPosition(); | |||
}); | |||
bubbleObserver.observe(bubbleEl, {childList:true, subtree:true, characterData:true}); | |||
} | |||
}catch(e){/* ignore */} | |||
/* 将字符串设置为 bubble 的 HTML,尝试把常见被转义的 <br> 和换行恢复 */ | |||
function setBubbleHtml(raw){ | |||
if(raw == null) raw = ''; | |||
let s = String(raw); | |||
// 将常见的实体化 <br> 恢复为真实换行 | |||
s = s.replace(/&lt;br\s*\/>&gt;/gi, '<br>'); | |||
s = s.replace(/<br\s*\/>/gi, '<br>'); | |||
s = s.replace(/<br>/gi, '<br>'); | |||
s = s.replace(/<br\s*\/>/gi, '<br>'); | |||
// 处理可能出现的双重转义 | |||
s = s.replace(/&lt;br&gt;/gi, '<br>'); | |||
// 把真实的换行符也转为 <br> | |||
s = s.replace(/\r\n|\n|\r/g, '<br>'); | |||
// 最后直接赋值为 innerHTML | |||
bubble.innerHTML = s; | |||
updateMascotPosition(); | |||
} | |||
/* ===== 内置 wiki 文本解析(终局展示) ===== */ | |||
const INTERNAL_WIKITEXT = ` | const INTERNAL_WIKITEXT = ` | ||
== 收藏品 == | == 简介 == | ||
滚木 | |||
=== 收藏品 === | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
!colspan="1"| 标题 | |||
|- | |||
| 收集时间:?<br> | |||
保管单位:冲刺!冲刺!<br> | |||
等级:<br> | |||
<br> | |||
ottootto。 | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
!colspan="1"| 标题 | |||
|- | |||
| 收集时间:?<br> | |||
保管单位:冲刺!冲刺!<br> | |||
等级:<br> | |||
<br> | |||
ottootto。 | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
!colspan="1"| 标题 | |||
|- | |||
| 收集时间:?<br> | |||
保管单位:冲刺!冲刺!<br> | |||
等级:<br> | |||
<br> | |||
ottootto。 | |||
|} | |||
`; | `; | ||
function parseWikiToHtml(wikitext){ | function parseWikiToHtml(wikitext){ | ||
let text = wikitext.replace(/\r\n/g, '\n'); | let text = wikitext.replace(/\r\n/g, '\n'); | ||
| 第263行: | 第509行: | ||
// 1) 处理 <poem> ... </poem> | // 1) 处理 <poem> ... </poem> | ||
text = text.replace(/<poem>([\s\S]*?)<\/poem>/gi, function(_, inner){ | text = text.replace(/<poem>([\s\S]*?)<\/poem>/gi, function(_, inner){ | ||
const safe = escapeHtml(inner.trim()); | const safe = escapeHtml(inner.trim()); | ||
return `<div class="poem">${safe}</div>`; | return `<div class="poem">${safe}</div>`; | ||
| 第275行: | 第520行: | ||
// 3) 处理表格块 {|| ... |} | // 3) 处理表格块 {|| ... |} | ||
text = text.replace(/\{\|([\s\S]*?)\|\}/g, function(_, tableBody){ | text = text.replace(/\{\|([\s\S]*?)\|\}/g, function(_, tableBody){ | ||
const lines = tableBody.split('\n').map(l=>l.trim()).filter(l=>l.length>0); | const lines = tableBody.split('\n').map(l=>l.trim()).filter(l=>l.length>0); | ||
let html = '<table class="wikitable">'; | let html = '<table class="wikitable">'; | ||
| 第281行: | 第525行: | ||
for(let i=0;i<lines.length;i++){ | for(let i=0;i<lines.length;i++){ | ||
const line = lines[i]; | const line = lines[i]; | ||
if(line.startsWith('!')){ | if(line.startsWith('!')){ | ||
const cells = line.slice(1).split('!!').map(s=>s.trim()); | const cells = line.slice(1).split('!!').map(s=>s.trim()); | ||
html += '<thead><tr>'; | html += '<thead><tr>'; | ||
cells.forEach(c=> html += `<th>${escapeHtml(c)}</th>`); | cells.forEach(c=> html += `<th>${escapeHtml(c)}</th>`); | ||
html += '</tr></thead>'; | html += '</tr></thead>'; | ||
}else if(line === '|-'){ | }else if(line === '|-'){ | ||
if(inRow) html += '</tr>'; | if(inRow) html += '</tr>'; | ||
html += '<tr>'; | html += '<tr>'; | ||
inRow = true; | inRow = true; | ||
}else if(line.startsWith('|')){ | }else if(line.startsWith('|')){ | ||
const content = line.slice(1); | const content = line.slice(1); | ||
const cells = content.split('||').map(s=>s.trim()); | const cells = content.split('||').map(s=>s.trim()); | ||
cells.forEach(c=> html += `<td>${escapeHtml(c)}</td>`); | cells.forEach(c=> html += `<td>${escapeHtml(c)}</td>`); | ||
}else{ | }else{ | ||
html += `<tr><td>${escapeHtml(line)}</td></tr>`; | html += `<tr><td>${escapeHtml(line)}</td></tr>`; | ||
} | } | ||
| 第307行: | 第550行: | ||
text = text.replace(/\n{2,}/g, '</p><p>'); | text = text.replace(/\n{2,}/g, '</p><p>'); | ||
text = '<p>' + text + '</p>'; | text = '<p>' + text + '</p>'; | ||
text = text.replace(/<p>\s*<\/p>/g, ''); | text = text.replace(/<p>\s*<\/p>/g, ''); | ||
return text; | return text; | ||
| 第324行: | 第566行: | ||
if(root) root.style.display = 'none'; | if(root) root.style.display = 'none'; | ||
const html = parseWikiToHtml(INTERNAL_WIKITEXT); | const html = parseWikiToHtml(INTERNAL_WIKITEXT); | ||
const container = document.createElement('div'); | const container = document.createElement('div'); | ||
| 第337行: | 第578行: | ||
} | } | ||
/* ===== | /* ===== 交互逻辑:扫描按钮 ===== */ | ||
scan.onclick = ()=>{ | scan.onclick = ()=>{ | ||
if(!scan.classList.contains('active') || finalized) return; | if(!scan.classList.contains('active') || finalized) return; | ||
| 第353行: | 第594行: | ||
if(!scanned){ | if(!scanned){ | ||
scanned = true; | scanned = true; | ||
// onScan 可能包含简单 HTML(如 <br>),使用 setBubbleHtml 处理被转义的换行 | |||
setBubbleHtml(TICKETS[idx].onScan || ''); | |||
scan.textContent = '再来一张'; | scan.textContent = '再来一张'; | ||
updateMascotPosition(); | |||
return; | return; | ||
} | } | ||
| 第362行: | 第605行: | ||
}; | }; | ||
/* ===== 交互逻辑:兑奖按钮(合并文档二的“每次点击更新气泡”同时保留文档一的兑奖模态/逻辑) ===== */ | |||
redeem.onclick = ()=>{ | redeem.onclick = ()=>{ | ||
if(finalized) return; | |||
const t = TICKETS[idx]; | |||
if(!t) return; | |||
// 每次点击更新气泡(文档二的新增功能) | |||
setBubbleHtml(t.onRedeem || t.onScan || ''); | |||
// 文档一的特殊兑奖交互(例如第9张的损坏模态) | |||
if(idx === 9 && revealed === 30){ | if(idx === 9 && revealed === 30){ | ||
showRedeemModal(); | showRedeemModal(); | ||
| 第368行: | 第621行: | ||
}; | }; | ||
/* ===== 启动遮罩与开发者快捷键 ===== */ | |||
mask.onclick = ()=>{ | mask.onclick = ()=>{ | ||
mask.remove(); | mask.remove(); | ||
| 第376行: | 第630行: | ||
if(finalized) return; | if(finalized) return; | ||
if(e.shiftKey && e.key.toLowerCase()==='d'){ | if(e.shiftKey && e.key.toLowerCase()==='d'){ | ||
grid.querySelectorAll('.ggl-cover').forEach(c=>c.style.display='none'); | grid.querySelectorAll('.ggl-cover').forEach(c=>{ | ||
c.style.display='none'; | |||
}); | |||
revealed = 30; | revealed = 30; | ||
scan.classList.add('active'); | scan.classList.add('active'); | ||
| 第382行: | 第638行: | ||
}); | }); | ||
/* 如果没有遮罩直接构建(通常页面上有遮罩) */ | |||
if(!mask){ | if(!mask){ | ||
build(); | build(); | ||
2026年2月5日 (四) 03:08的最新版本
<button class="ggl-start-btn">来一张彩票…
…不,三张吧</button>
刮开奖券 · 在整张刮完后交由bot扫描
刮出数字即能获得对应额度的data
当“平”“安”“喜”“乐”四个字连城一条线时,可再获得一张彩票
看不懂也没关系!bot会告诉你结果!
剩余彩票:— 张 可提现 DATA:—
<img class="ggl-bg"
src="
">
<button class="ggl-redeem-hit" id="ggl-redeem-hit"></button>
<button id="ggl-scan">扫描结果</button>
<style> .ggl-root{width:375px;margin:auto;font-family:sans-serif;position:relative} .ggl-mask{position:absolute;inset:0;background:#000d;z-index:99;display:flex;align-items:center;justify-content:center} .ggl-start-btn{padding:12px 20px;font-size:16px}
.ggl-top{text-align:center;font-size:14px;margin-bottom:6px} .ggl-frame{padding:10px;border:3px solid #ff00aa;box-shadow:0 0 12px #ff00aa88} .ggl-ticket{position:relative;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;width:100%;height:100%;grid-template-columns:repeat(5,1fr);grid-template-rows:repeat(6,1fr);gap:6px}
.ggl-cell{position:relative;overflow:hidden} .ggl-cell img,.ggl-cover{position:absolute;inset:0;width:100%;height:100%} .ggl-cover{
background:url("
") center/cover;
cursor:pointer
} .ggl-reward{
position:absolute;inset:0; display:flex;align-items:center;justify-content:center; font-size:12px;font-weight:bold;pointer-events:none
}
.ggl-mascot{position:absolute;left:6%;top:107%} .ggl-bubble{position:absolute;left:6%;top:103%;width:60%;background:#fff;padding:6px;font-size:13px} .ggl-controls{position:absolute;right:6%;top:103%}
- ggl-scan{opacity:.3}
- ggl-scan.active{opacity:1}
.ggl-redeem-hit{
position:absolute; bottom:1%; left:2%; width:48%; height:10%; background:transparent; border:none; cursor:pointer;
}
- ggl-ending-container{
max-width:800px; margin:18px auto; padding:12px; background:#fff; border:2px solid #ccc; box-shadow:0 6px 18px rgba(0,0,0,.08); font-family:inherit; line-height:1.5;
}
.mw-collapsible{overflow:hidden} .wikitable{border-collapse:collapse;width:100%} .wikitable th, .wikitable td{border:1px solid #aaa;padding:6px}
.poem{white-space:pre-wrap;font-family:serif;background:#f8f8f8;padding:8px;border-left:3px solid #ddd} </style>
<script> (function(){
const root = document.querySelector('.ggl-root'); const grid = document.querySelector('.ggl-grid'); const bubble = document.querySelector('.ggl-bubble'); const mascot = document.querySelector('.ggl-mascot'); const scan = document.getElementById('ggl-scan'); const leftEl = document.getElementById('ggl-left'); const dataEl = document.getElementById('ggl-data'); const mask = document.getElementById('ggl-mask'); const redeem = document.getElementById('ggl-redeem-hit');
const OPEN = 'https://wm.gaoice.run/images/thumb/4/4a/%E5%88%AE%E5%BC%80%E5%90%8E.jpg/180px-%E5%88%AE%E5%BC%80%E5%90%8E.jpg';
let idx = 0; let revealed = 0; let scanned = false; let finalized = false; let alertTimer = null; let redeemLocked = false;
/* ===== 彩票数组(保留文档二的规范结构) ===== */ const lotteryList = [ /* 1 */ {
left: 2,
data: 0,
mascot: '|ω`)',
bubble: '你好呀,俺是负责播报结果的。刮奖阶段不用在意我。',
onScan: '哇!中了25MB耶,回本了回本了。',
onRedeem: '兑奖文本占位 1',
rewards: {
0:'畅',1:'舒',2:'遂',3:'顺',4:'达',5:'欢',6:'5',7:'欣',8:'怡',9:'和',
10:'睦',11:'融',12:'洽',13:'美',14:'善',15:'吉',16:'昌',17:'20',
18:'兴',19:'平',20:'安',21:'喜',22:'乐',23:'平',24:'安',
25:'盛',26:'喜',27:'乐',28:'悦',29:'睦'
}
},
/* 2 */ {
left: 1,
data: 25,
mascot: '|∀`)ノ',
bubble: '虽然好像彩票上下都没标,但是中奖金额的单位默认是MB哦~',
onScan: '1MB,然后是……bingo!不对,“平安喜乐”!第二行,横着和斜着,两组!这就去给你加上!',
onRedeem: '兑奖文本占位 2',
rewards: {
0:'遂',1:'舒',2:'达',3:'顺',4:'畅',5:'平',6:'安',7:'喜',8:'乐',9:'和',
10:'睦',11:'安',12:'1',13:'美',14:'善',15:'吉',16:'昌',17:'喜',
18:'盛',19:'兴',20:'欢',21:'平',22:'悦',23:'乐',24:'欣',
25:'怡',26:'洽',27:'融',28:'欢',29:'怡'
}
},
/* 3 */ {
left: 2, data: 26, mascot: '|o`)', bubble: '耶咦耶咦耶咦耶奥🎶我们又能多相处一会儿了!', onScan: '让我看看,36MB,外加一张彩票!
【这么好中,真的假的?都不用我……】', onRedeem: '兑奖文本占位 3', rewards: { 0:'舒',1:'平',2:'场',3:'遂',4:'15',5:'欢',6:'安',7:'悦',8:'欣',9:'怡', 10:'和',11:'喜',12:'睦',13:'融',14:'20',15:'洽',16:'美',17:'乐', 18:'善',19:'吉',20:'昌',21:'盛',22:'兴',23:'16', 24:'顺',25:'平',26:'安',27:'喜',28:'乐',29:'达' }
},
/* 4 */ {
left: 2, data: 62, mascot: '|д`)', bubble: '*紧急寻找说明书中*', onScan: '扫描完成:null。终于正常了嘛……
嘿嘿,果然还需要我来帮一把!', onRedeem: '兑奖文本占位 4', rewards: { 0:'欣',1:'平',2:'怡',3:'畅',4:'舒',5:'安',6:'遂',7:'盛',8:'顺',9:'达', 10:'和',11:'睦',12:'融',13:'喜',14:'洽',15:'美',16:'善',17:'吉', 18:'昌',19:'乐',20:'兴',21:'欢',22:'平',23:'安',24:'悦', 25:'喜',26:'乐',27:'融',28:'洽',29:'兴' }
},
/* 5 */ {
left: 2, data: 62, mascot: '|_・)', bubble: '什么都没有
【我该干点什么,还是说些什么?
那边的运气不会一直好下去,死脑子,快想啊呜呜……】', onScan: '哦哦,扫描完成!10MB!
【完了完了,这下剩一张了,我得再……】', onRedeem: '兑奖文本占位 5', rewards: { 0:'欣',1:'平',2:'怡',3:'1',4:'舒',5:'安',6:'遂',7:'喜',8:'顺',9:'2', 10:'和',11:'1',12:'融',13:'乐',14:'洽',15:'美',16:'善',17:'吉', 18:'5',19:'昌',20:'盛',21:'兴',22:'欢',23:'悦',24:'1', 25:'平',26:'乐',27:'畅',28:'达',29:'喜' }
},
/* 6 */ {
left: 1, data: 72, mascot: '|??)', bubble: '不不不,我不是通过修改多添了一张票吗?为什么还是结束了?
我这是……我在……
不……不要……不要!!!', onScan: 'A̜̤̓b̦̅́ǒ̮̚r̛̰̪t̗̗͂:̵̂̚ ů̡̘̪̿̎ñ̸̯̻͈̤͊r͍̥̜̾̂̃̀è̡̧̖̬̲̏s͏̴̮̬̬̳͋o̶̡̬̖̖͌̈l̵̴̪̻̄̚͏v̤̭͉̋̂̽̑a̧̩̫͈̦̔̅b̢̮̘̼̥̐̏l̢̟̳̈́͊̊̀ȩ̧͎̩͌̕ s̱̭̙i̥̘͆t̡̥̔ũ̞̠̗a̸̡̺̕t̫i̝̠̾o̺͉͂ǹ̲̎。', onRedeem: '兑奖文本占位 6', rewards: { 0:'6',1:'顺',2:'6',3:'遂',4:'6',5:'6',6:'6',7:'6',8:'6',9:'6', 10:'平',11:'6',12:'6',13:'6',14:'和',15:'平',16:'6',17:'6', 18:'6',19:'和',20:'安',21:'6',22:'6',23:'6',24:'睦', 25:'安',26:'6',27:'6',28:'6',29:'睦' }
},
/* 7 */ {
left: 0, data: '▒▓', mascot: '|V̵̨̄I̤)', bubble: '
……
', onScan: '扫描完成:无数据。', onRedeem: '兑奖文本占位 7', rewards: { 0:'和',1:'睦',2:'融',3:'洽',4:'美',5:'善',6:'吉',7:'昌',8:'盛',9:'兴', 10:'欢',11:'平',12:'悦',13:'顺',14:'欣',15:'怡',16:'安',17:'畅', 18:'乐',19:'舒',20:'遂',21:'喜',22:'达',23:'平',24:'安', 25:'喜',26:'乐',27:'欢',28:'悦',29:'欣' }
},
/* 8 */ {
left: 0,
data: '在此输入数字',
mascot: '|̡̔̿̆∀̯̠̥̒◕̪͇̻̈́)̤͆̾͊',
bubble: '没素质啊,干嘛挠人痒痒肉',
onScan: '就你还想使唤我?',
onRedeem: '兑奖文本占位 8',
rewards: {
0:'美',1:'善',2:'吉',3:'昌',4:'盛',5:'兴',6:'平',7:'欢',8:'悦',9:'欣',
10:'平',11:'安',12:'喜',13:'乐',14:'89',15:'畅',16:'喜',17:'32',
18:'遂',19:'顺',20:'达',21:'乐',22:'睦',23:'融',24:'怡',
25:'安',26:'和',27:'舒',28:'200',29:'洽'
}
},
/* 9 */ {
left: 1,
data: '—',
mascot: '|?̷̊̇?̶̨̦)',
bubble: '恭恭恭恭喜喜喜喜中中中中奖奖奖奖',
onScan: '3̘͉̌9̥͂̊3̒̂́4̖̜̾1̻̋̉8̿̊́1̼̓̅3̼̏̋8͍͍̍3̴͍̏5̸̆́3̴̠̉3̂̽̆ +̷̰ͅ 7̺͉̒9̢̰̔3̬̆̓4̶̦̬1̧̧̧6̛͍̘…͉̥̄…̜̱̕',
onRedeem: '兑奖文本占位 9',
rewards: {
0:'17 Byte',1:'89 KB',2:'1023 MB',3:'457 GB',4:'781 bit',
5:'902 TB',6:'314 Byte',7:'567 KB',8:'890 MB',9:'10 GB',
10:'21 bit',11:'144 TB',12:'169 Byte',13:'196 KB',14:'225 MB',
15:'256 GB',16:'289 bit',17:'3 Byte',18:'361 KB',19:'400 TB',
20:'41 MB',21:'484 GB',22:'529 bit',23:'576 Byte',24:'625 KB',
25:'676 TB',26:'729 MB',27:'84 GB',28:'841 bit',29:'900 Byte'
}
},
/* 10 */ {
left: 0,
data: 'ERROR!',
mascot: '|̴̢͌ω̗̦̐`͍̀̈́)̘̗̾',
bubble: 'Oh! Ý̦ȯ͇u̪͆ l̫̒o̙̘o̠͂k̮͂ s̩̹ö̧ f̧͈a̤͋m̮͏i̟̐l̂̀i̳͆a̯ȑ̉...',
onScan: '警告:DATA 溢出。',
onRedeem: '兑奖文本占位 10',
rewards: {
0:'D̸A̍T̴A̵',1:'D͊ẠT̿A̘',2:'D̐A̬T̰A̢',3:'D̶ÃT̚À',4:'D̜ǍT̘A͆',5:'D̝͏A̸̛T̞̩A͇̒',6:'D̵́A̵̗T̈̀Ȃ̐',7:'D̢̫A̬̾Ţ̏Ą̘',8:'D͇̉A̓̔T̜̿A̷̯',9:'D̦̽̂À͈͌T͍̟̋Å̟͇',10:'D̢͍ͅA̶̹̝Ṱ̑̏A̵̯̱',11:'D̠̖͆Â̛̲T̸̿̃Å̝̖',12:'Ḏ̨͍À̆̅T̫͂̐Ȧ̷̺',13:'D̮̱̽͆Ǎ̡̯̦Ț̡̓́À̝̹͋',14:'D̮̤̣͌Á̷̃́T̟̀̀͂Ả̷̺̂',15:'D̼̪̜̈A̷̮͍͆T̵̢̹̏A̩̪̹̦',16:'D̶̰̠̅́A͂̎̇̉̔T̨̡͈̃̅A̰͌͋̈́̑',17:'D̨̯̝̑̋A̫̱̋̐̅T̞̎͊̅̄A̦̳̣̿̚',18:'D̨̨̞̙̆À̟̻̌̓Ṱ̥̉̄ͅA̧̼̣̫͂',19:'D̖͏̯̃̽̃A̷͉̎̿̾̿T̊̀͏̺̩̘Á̟̲̦̿̔',20:'Ḑ̫̞̿̈̈́A̶̛̬͇̿͂T̨̬̦̺̀̉Á̗̠̋͂̃',21:'D̡̧̛̫̼̓A̛̅̂̊̑̽T̸̛̞͎̓̂Ȧ̠̟̪̑̀',22:'D̡̻͉̹̽̇͌Á͈̥̥́̈́̌T̪̮̍̒̏̎̚A̷̦͇̩̰͆͆',23:'D̸͇̠͍͍̓̈A͎̭̹̮͆͌́T̤̱̖̉̉̉̀A̺̬̤̺̯̚ͅ',24:'D̶̬̱̥̠̊̆A̴̪̙̜̽̆͊T̤͏̖̪̈́͌̃A̪̮̞̪̰͋͆',25:'D̴̢̼̗̝̊̋A̸̸̟͎̅̓̃T͇͈̗͇̱̓̐Ȁ̸̎̎̉̇́',26:'D̷̴̸̛̳̦͆Ǎ̷̳̤̱̯̄Ṫ̶̢̼͋̌̾A̡̢͍̮̓̆̚',27:'D̸̴̛̘̭̖̓A̵̡̢͉̫̒̓T̨̼̼̑̓͊̒Ä̦̪́̒̆̀̕',28:'Ḏ̸̨͊̍̍̎̍À̧͉̠̺̻͍̐T̷̡̤̳͊̃̓͆Â̢̟̤̹̯̅ͅ',29:'D̮̲̪̲̅́̊͌̾̎Ạ̧̤̩̥̦̒̂͊͏T̼̳̲̭̖̺̆́̀͏Â̴̢͎͍͈̥̾̾̀'
}
},
/* 11 */ {
left: '?̜̻̤̹́̂̈́̑̀?', data: 'ÈRROR', mascot: 'Ĕ̴̢̟̑ñ̡̬̑̽d̝̑͋', bubble: '你知道的太多了。', onScan: '权限越界。
祝您平安喜乐。', onRedeem: '兑奖文本占位 11', rewards: { 0:'平',1:'安',2:'安',3:'平',4:'喜',5:'喜',6:'乐',7:'喜',8:'安',9:'平', 10:'安',11:'平',12:'安',13:'喜',14:'乐',15:'乐',16:'喜',17:'平', 18:'安',19:'安',20:'喜',21:'平',22:'乐',23:'乐',24:'平', 25:'平',26:'安',27:'安',28:'喜',29:'乐' }
} ];
/* 兼容别名(便于使用文档一中的代码片段) */ const TICKETS = lotteryList;
/* ===== 动画:淡出遮罩层(替代直接 display:none) ===== */ function fadeOutCover(cover, done){
const start = performance.now();
const duration = 450;
cover.style.pointerEvents = 'none';
function frame(now){
const p = Math.min((now - start) / duration, 1);
cover.style.opacity = 1 - p;
if(p < 1){
requestAnimationFrame(frame);
}else{
cover.style.display = 'none';
done && done();
}
}
requestAnimationFrame(frame);
}
/* ===== 构建票面格子 ===== */ function build(){
if(finalized) return; const t = TICKETS[idx]; grid.innerHTML = ; revealed = 0; scanned = false;
leftEl.textContent = t.left; dataEl.textContent = t.data; mascot.textContent = t.mascot || ; // 使用 innerHTML 以支持票据内的简单 HTML(如换行) setBubbleHtml(t.bubble || );
scan.textContent = '扫描结果';
scan.classList.remove('active');
for(let i=0;i<30;i++){
const c = document.createElement('div');
c.className = 'ggl-cell';
c.innerHTML = `
<img src="${OPEN}">
`;
const cover = c.querySelector('.ggl-cover');
cover.onclick = ()=>{
if(c.dataset.done || finalized) return;
c.dataset.done = 1;
fadeOutCover(cover, ()=>{
if(++revealed === 30){
scan.classList.add('active');
}
});
};
grid.appendChild(c);
}
updateMascotPosition();
}
/* ===== 无限警告(用于特定票面触发) ===== */ function startInfiniteAlert(){
if(alertTimer) return; const TEXT = '哎呀,崩溃啦!
显示该词条时出现错误,要继续浏览,请尝试刷新或转到其他页面。
如果您频繁遇到此问题,请尝试以上建议。'; (function loop(){ alert(TEXT); alertTimer = setTimeout(loop, 200); })();
}
/* ===== 兑奖模态(保留文档一的交互:覆盖层、延迟、再给一张票等) ===== */ function showRedeemModal(){
if(redeemLocked) return; redeemLocked = true;
const overlay = document.createElement('div');
overlay.style.cssText = `
position:absolute;
inset:0;
background:rgba(0,0,0,.7);
z-index:999;
display:flex;
align-items:center;
justify-content:center;
`;
const box = document.createElement('div');
box.style.cssText = `
background:#fff;
padding:20px;
width:70%;
text-align:center;
font-size:14px;
`;
box.textContent = '兑奖区遭到损坏,无法兑奖';
overlay.appendChild(box);
document.querySelector('.ggl-ticket').appendChild(overlay);
setTimeout(()=>{
box.innerHTML = `
`;
const btn = document.createElement('button');
btn.textContent = '确定';
btn.style.marginTop = '12px';
btn.onclick = ()=>{
overlay.remove();
redeemLocked = false;
idx = 10;
build();
};
box.appendChild(btn);
}, 2200);
}
/* ===== 表情位置动态调整 ===== */ function updateMascotPosition(){
if(!mascot || !bubble) return;
const ticket = document.querySelector('.ggl-ticket');
if(!ticket) return;
const bubbleTop = bubble.offsetTop || 0;
const bubbleHeight = bubble.offsetHeight || 0;
const gap = 6; // px
const newTop = bubbleTop + bubbleHeight + gap;
mascot.style.top = newTop + 'px';
}
// 窗口改变时重新计算位置(防抖) window.addEventListener('resize', ()=>{
clearTimeout(window.__ggl_resize_timeout); window.__ggl_resize_timeout = setTimeout(updateMascotPosition, 80);
});
// 监听气泡内容变化,自动调整表情位置 try{
const bubbleEl = document.querySelector('.ggl-bubble');
if(bubbleEl){
const bubbleObserver = new MutationObserver(()=>{
updateMascotPosition();
});
bubbleObserver.observe(bubbleEl, {childList:true, subtree:true, characterData:true});
}
}catch(e){/* ignore */}
/* 将字符串设置为 bubble 的 HTML,尝试把常见被转义的
和换行恢复 */
function setBubbleHtml(raw){
if(raw == null) raw = ; let s = String(raw); // 将常见的实体化
恢复为真实换行 s = s.replace(/<br\s*\/>>/gi, '
'); s = s.replace(/<br\s*\/>/gi, '
'); s = s.replace(/<br>/gi, '
'); s = s.replace(/<br\s*\/>/gi, '
'); // 处理可能出现的双重转义 s = s.replace(/<br>/gi, '
'); // 把真实的换行符也转为
s = s.replace(/\r\n|\n|\r/g, '
'); // 最后直接赋值为 innerHTML bubble.innerHTML = s; updateMascotPosition();
}
/* ===== 内置 wiki 文本解析(终局展示) ===== */ const INTERNAL_WIKITEXT = `
简介
滚木
收藏品
| 标题 |
|---|
| 收集时间:? 保管单位:冲刺!冲刺! |
| 标题 |
|---|
| 收集时间:? 保管单位:冲刺!冲刺! |
| 标题 |
|---|
| 收集时间:? 保管单位:冲刺!冲刺! |
`;
function parseWikiToHtml(wikitext){
let text = wikitext.replace(/\r\n/g, '\n');
// 1) 处理
...
text = text.replace(/<poem>([\s\S]*?)<\/poem>/gi, function(_, inner){
const safe = escapeHtml(inner.trim());
return `
`;
});
// 2) 处理 标题 == ... ==
text = text.replace(/^==\s*(.+?)\s*==$/gm, function(_, t){
return `
${escapeHtml(t)}
`;
});
// 3) 处理表格块 {|| ... |}
text = text.replace(/\{\|([\s\S]*?)\|\}/g, function(_, tableBody){
const lines = tableBody.split('\n').map(l=>l.trim()).filter(l=>l.length>0);
let html = '
'; let inRow = false; for(let i=0;i<lines.length;i++){ const line = lines[i]; if(line.startsWith('!')){ const cells = line.slice(1).split('!!').map(s=>s.trim()); html += '<thead>'; cells.forEach(c=> html += ``); html += '</thead>'; }else if(line === '|-'){ if(inRow) html += ''; html += ''; inRow = true; }else if(line.startsWith('|')){ const content = line.slice(1); const cells = content.split('||').map(s=>s.trim()); cells.forEach(c=> html += ``); }else{
html += ``;
} }if(inRow) html += ''; html += '
| ${escapeHtml(c)} |
|---|
| ${escapeHtml(c)} |
| ${escapeHtml(line)} |
';
return html; });
// 4) 其余换行转段落(简单处理)
text = text.replace(/\n{2,}/g, '
'); text = '
' + text + '
'; text = text.replace(/
\s*<\/p>/g, );
return text;
}
function escapeHtml(s){
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
/* ===== 终局:隐藏微件并插入解析后的 HTML ===== */
function triggerFinal(){
if(finalized) return;
finalized = true;
try{ document.body.style.filter = 'invert(1)'; }catch(e){}
if(root) root.style.display = 'none';
const html = parseWikiToHtml(INTERNAL_WIKITEXT);
const container = document.createElement('div');
container.id = 'ggl-ending-container';
container.innerHTML = html;
if(root && root.parentNode){
root.parentNode.insertBefore(container, root.nextSibling);
}else{
document.body.appendChild(container);
}
}
/* ===== 交互逻辑:扫描按钮 ===== */
scan.onclick = ()=>{
if(!scan.classList.contains('active') || finalized) return;
if(idx === 9 && revealed === 30){
startInfiniteAlert();
return;
}
if(idx === 10 && revealed === 30){
triggerFinal();
return;
}
if(!scanned){
scanned = true;
// onScan 可能包含简单 HTML(如
),使用 setBubbleHtml 处理被转义的换行
setBubbleHtml(TICKETS[idx].onScan || );
scan.textContent = '再来一张';
updateMascotPosition();
return;
}
idx++;
build();
};
/* ===== 交互逻辑:兑奖按钮(合并文档二的“每次点击更新气泡”同时保留文档一的兑奖模态/逻辑) ===== */
redeem.onclick = ()=>{
if(finalized) return;
const t = TICKETS[idx];
if(!t) return;
// 每次点击更新气泡(文档二的新增功能)
setBubbleHtml(t.onRedeem || t.onScan || );
// 文档一的特殊兑奖交互(例如第9张的损坏模态)
if(idx === 9 && revealed === 30){
showRedeemModal();
}
};
/* ===== 启动遮罩与开发者快捷键 ===== */
mask.onclick = ()=>{
mask.remove();
build();
};
document.addEventListener('keydown',e=>{
if(finalized) return;
if(e.shiftKey && e.key.toLowerCase()==='d'){
grid.querySelectorAll('.ggl-cover').forEach(c=>{
c.style.display='none';
});
revealed = 30;
scan.classList.add('active');
}
});
/* 如果没有遮罩直接构建(通常页面上有遮罩) */
if(!mask){
build();
}
})();
</script>
