微件:GGLScratchGame:修订间差异

来自Limbo Wiki Mirror
Gaoice留言 | 贡献
无编辑摘要
标签(旧)WikiEditor
无编辑摘要
标签(旧)WikiEditor
 
(未显示2个用户的58个中间版本)
第1行: 第1行:
<!DOCTYPE html>
<div class="ggl-root" id="ggl-root">
<html>
<head>
    <meta charset="UTF-8">
    <style>
        .scratch-lottery-container {
            font-family: 'Arial', sans-serif;
            max-width: 1100px;
            margin: 20px auto;
            background: #f5f5f5;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }


        .scratch-lottery-header {
  <!-- 初始化遮罩 -->
            text-align: center;
  <div class="ggl-mask" id="ggl-mask">
            margin-bottom: 20px;
    <button class="ggl-start-btn">来一张彩票…<br>…不,三张吧</button>
        }
  </div>


        .scratch-lottery-header h2 {
  <!-- 顶部 -->
            margin: 0 0 10px 0;
  <div class="ggl-top">
            color: #333;
    <div class="ggl-rule">
            font-size: 24px;
      刮开奖券 · 在整张刮完后交由bot扫描<br>
        }
      刮出数字即能获得对应额度的data<br>
      当“平”“安”“喜”“乐”四个字连城一条线时,可再获得一张彩票<br>
      看不懂也没关系!bot会告诉你结果!
    </div>
    <div class="ggl-left">
      剩余彩票:<span id="ggl-left">—</span> 张 
      可提现 DATA:<span id="ggl-data">—</span>
    </div>
  </div>


        .scratch-lottery-status {
  <div class="ggl-frame">
            display: flex;
    <div class="ggl-ticket">
            justify-content: space-around;
            margin: 15px 0;
            font-size: 14px;
            color: #666;
        }


        .status-item {
      <img class="ggl-bg"
            text-align: center;
        src="https://wm.gaoice.run/images/b/b6/%E5%9B%BE%E7%89%871.png">
        }


        .status-label {
      <div class="ggl-scratch-area">
            font-weight: bold;
        <div class="ggl-grid"></div>
            color: #333;
      </div>
            display: block;
            font-size: 12px;
            margin-bottom: 4px;
        }


        .status-value {
      <button class="ggl-redeem-hit" id="ggl-redeem-hit"></button>
            font-size: 20px;
            color: #ff6b35;
        }


        /* 彩票主容器 */
      <div class="ggl-mascot"></div>
        .lottery-ticket-wrapper {
      <div class="ggl-bubble"></div>
            position: relative;
            margin: 20px auto;
            display: inline-block;
            width: 100%;
            max-width: 540px;
            background: white;
            border-radius: 4px;
            overflow: hidden;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
        }


         .lottery-bg-img {
      <div class="ggl-controls">
            display: block;
         <button id="ggl-scan">扫描结果</button>
            width: 100%;
      </div>
            height: auto;
            background: #fff;
        }


        /* 刮奖区域容器(黄色块位置) */
    </div>
        .scratchable-area {
  </div>
            position: absolute;
</div>
            left: 10.6%;
            top: 23.6%;
            width: 78.6%;
            height: 53.4%;
            background: transparent;
        }


        /* 30 个格子网格 */
<style>
        .tile-grid {
/* 原样样式 */
            display: grid;
.ggl-root{width:375px;margin:auto;font-family:sans-serif;position:relative}
            grid-template-columns: repeat(5, 1fr);
.ggl-mask{position:absolute;inset:0;background:#000d;z-index:99;display:flex;align-items:center;justify-content:center}
            grid-template-rows: repeat(6, 1fr);
.ggl-start-btn{padding:12px 20px;font-size:16px}
            gap: 0;
            width: 100%;
            height: 100%;
            padding: 0;
        }


        /* 单个格子 */
.ggl-top{text-align:center;font-size:14px;margin-bottom:6px}
        .tile {
.ggl-frame{padding:10px;border:3px solid #ff00aa;box-shadow:0 0 12px #ff00aa88}
            position: relative;
.ggl-ticket{position:relative;aspect-ratio:1075/1911}
            aspect-ratio: 1;
.ggl-bg{width:100%;display:block}
            background: #000;
            cursor: pointer;
            border: 1px solid rgba(255,255,255,0.2);
            overflow: hidden;
            transition: all 0.2s ease;
        }


        .tile:hover:not(.revealed) {
.ggl-scratch-area{position:absolute;left:10%;top:35%;width:80%;height:53%}
            background: #1a1a1a;
.ggl-grid{display:grid;width:100%;height:100%;grid-template-columns:repeat(5,1fr);grid-template-rows:repeat(6,1fr);gap:6px}
            box-shadow: inset 0 0 8px rgba(255,255,255,0.3);
        }


        .tile-cover {
.ggl-cell{position:relative;overflow:hidden}
            position: absolute;
.ggl-cell img,.ggl-cover{position:absolute;inset:0;width:100%;height:100%}
            inset: 0;
.ggl-cover{
            display: flex;
  background:url("https://wm.gaoice.run/images/thumb/5/5a/%E5%88%AE%E5%BC%80%E5%89%8D.png/180px-%E5%88%AE%E5%BC%80%E5%89%8D.png") center/cover;
            align-items: center;
  cursor:pointer
            justify-content: center;
}
            background: #000;
.ggl-reward{
            font-size: 24px;
  position:absolute;inset:0;
            font-weight: bold;
  display:flex;align-items:center;justify-content:center;
            color: #666;
  font-size:12px;font-weight:bold;pointer-events:none
            opacity: 1;
}
            transition: opacity 0.3s ease;
            pointer-events: none;
        }


        .tile-cover img {
.ggl-mascot{position:absolute;left:6%;top:107%}
            max-width: 100%;
.ggl-bubble{position:absolute;left:6%;top:103%;width:60%;background:#fff;padding:6px;font-size:13px}
            max-height: 100%;
.ggl-controls{position:absolute;right:6%;top:103%}
            object-fit: contain;
#ggl-scan{opacity:.3}
        }
#ggl-scan.active{opacity:1}


        .tile.revealed .tile-cover {
.ggl-redeem-hit{
            opacity: 0;
  position:absolute;bottom:1%;left:2%;
            pointer-events: none;
  width:48%;height:10%;
        }
  background:transparent;border:none
}


        .tile-reveal {
            position: absolute;
            inset: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #ffd700;
            opacity: 0;
            transition: opacity 0.3s ease;
            pointer-events: none;
        }


        .tile-reveal img {
#ggl-ending-container{
            max-width: 100%;
  max-width:800px;
            max-height: 100%;
  margin:18px auto;
            object-fit: contain;
  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;
}


        .tile.revealed .tile-reveal {
.mw-collapsible{overflow:hidden}
            opacity: 1;
.wikitable{border-collapse:collapse;width:100%}
        }
.wikitable th, .wikitable td{border:1px solid #aaa;padding:6px}


        .tile-text {
.poem{white-space:pre-wrap;font-family:serif;background:#f8f8f8;padding:8px;border-left:3px solid #ddd}
            position: absolute;
</style>
            inset: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: #333;
            font-weight: bold;
            text-align: center;
            padding: 4px;
            word-break: break-word;
        }


        /* 气泡文本 */
<script>
        .bubble {
(function(){
            position: fixed;
            background: white;
            border: 2px solid #333;
            border-radius: 8px;
            padding: 12px 16px;
            font-size: 13px;
            color: #333;
            max-width: 200px;
            word-wrap: break-word;
            z-index: 1000;
            box-shadow: 0 4px 12px rgba(0,0,0,0.2);
            animation: bubbleAppear 0.3s ease;
            pointer-events: none;
        }


        .bubble::before {
const root  = document.querySelector('.ggl-root');
            content: '';
const grid  = document.querySelector('.ggl-grid');
            position: absolute;
const bubble = document.querySelector('.ggl-bubble');
            bottom: -8px;
const mascot = document.querySelector('.ggl-mascot');
            left: 20px;
const scan  = document.getElementById('ggl-scan');
            width: 0;
const leftEl = document.getElementById('ggl-left');
            height: 0;
const dataEl = document.getElementById('ggl-data');
            border-left: 8px solid transparent;
const mask  = document.getElementById('ggl-mask');
            border-right: 8px solid transparent;
const redeem = document.getElementById('ggl-redeem-hit');
            border-top: 8px solid #333;
        }


        .bubble::after {
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';
            content: '';
            position: absolute;
            bottom: -4px;
            left: 22px;
            width: 0;
            height: 0;
            border-left: 6px solid transparent;
            border-right: 6px solid transparent;
            border-top: 6px solid white;
        }


        .bubble.top {
let idx = 0;
            bottom: auto;
let revealed = 0;
        }
let scanned = false;
let finalized = false;
let alertTimer = null;
let redeemLocked = false;


        .bubble.top::before {
const TICKETS = [
            bottom: auto;
/* 1 */
            top: -8px;
  {left:2,data:0,mascot:'|ω`)',bubble:'你好呀,俺是负责播报结果的。不用管我。',onScan:'哇!中了25MB耶,回本了回本了。',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:'睦'}},
            border-top: none;
/* 2 */
            border-bottom: 8px solid #333;
  {left:1,data:25,mascot:'|∀`)ノ',bubble:'虽然好像彩票上下都没标,但是中奖金额的单位默认是MB哦~',onScan:'1MB,然后是……bingo!不对,“平安喜乐”!第二行,横着和斜着,两组!这就去给你加上!',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>(小声)这么好中,真的假的?都不用我……。',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:'*suisuinian,sikaozijidenengli|_・)',onScan:'扫描完成:null。终于正常了嘛……<br>嘿嘿,果然还需要我来帮一把!',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:'扫描完成:',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:5,mascot:'|??)',bubble:'不不不,我不是通过修改多添了一张票吗?为什么还是结束了?<br>我这是……我在……<br>不……不要……不要!!!',onScan:'A̜̤̓b̦̅́ǒ̮̚r̛̰̪t̗̗͂:̵̂̚ ů̡̪n̯̻͊r̥̂̀e̡̧̲s̴̬͋o̬̖̖l̴̻̚v̭̋̽a̫͈̅b̮̼̏l̟̊̀ȩ͎͌ s̱̭̙i̥̘͆t̡̥̔u̸̟̙a̤͊̓t̫̒́i̝̠̾o̺͉͂ǹ̲̎。',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:5,mascot:'',bubble:'<br>.̨̝̮̮͉̖̃̿̈́ͅ.̢̦̫͆͌͆͏̨̩͉.͏̤̫̣̎̆̃̾́ͅ.̧̖̻̥͈̥̈̂̌̒.̲̹́̋̄̐̈́ͅͅ͏.̡͇͈̣̓͌͌͌̂̓.̖̩͈̻̱̌͋͆̊̚.̮̦̝̼̤̮͈͂̆̑.̵̧̘̲̞̉͋̇͂̕.̢̨͌̿͏̖̳͌̓̎.̙̤̫͉̔͋̊̄̐ͅ.͏̶̺̦̲̝̍̈́͌̚.̳̜̼̼̻̹̐̃̈̑.̨̠͎̝̟̼͇̞̩̃.͎̟͉̠̫͉̜̿̈́̓.̷̛̜̦̩̼̎̏̈́͆.̡̨̢̭͇̣̿̓̏͏.̰̻͇͉̑̌̓̆̅̄.̅͏̺̫̱̯̳̹̓̏.̸̨̢̦̙͌̓̉̃̉.̨̛̻̬̈̔́̍̃͌.̝͈̠͇̣̭̐̈̓̍.̴͎̰̼̾͆̃̍̃̃.̛̼͉̝̃̔̆̆̽̚.̷̡̮̠̥̳̬̇̓̃.̞͎̗̀͂̌͊̂̈ͅ.̵̴̱̫̟̒̓̅͊̍.̮̺̠̯͉̊̅̓̀̓.̴̧̨̬̳̬́͋́̂.̤̠̲̍̓ͅ͏̶̾͏<br>',onScan:'扫描完成:无数据。',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:7,mascot:'|∀◕。)',bubble:'没素质啊,干嘛挠我',onScan:'jiuni?',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:'▒▓░▒▓▒▓▒▓3934181383533 + 793416……',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:'你是谁?',onScan:'扫描结果:DATA 溢出。',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:'È̶̶̶̝͏̶̶̶̝̞R̶̶̶̶̶̶̝̬̩̦̈R̶̶̶̶̶̵̶̗̹̄̈Ơ̶̶̶̶̶̶̞̳̑̆R̶̶̼͏̶̴̶̶̶̢̲!̶̶̶̶̶̶̜̪̏̊̋',mascot:'平安喜乐',bubble:'你知道的太多了。',onScan:'权限越界。',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:'乐'}}
];


        .bubble.top::after {
function fadeOutCover(cover, done){
            bottom: auto;
  const start = performance.now();
            top: -4px;
  const duration = 450;
            border-top: none;
  cover.style.pointerEvents = 'none';
            border-bottom: 6px solid white;
  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);
}


        @keyframes bubbleAppear {
function build(){
            from {
  if(finalized) return;
                opacity: 0;
  const t = TICKETS[idx];
                transform: scale(0.8);
  grid.innerHTML = '';
            }
  revealed = 0;
            to {
  scanned = false;
                opacity: 1;
                transform: scale(1);
            }
        }


        /* 吉祥物按钮 + 扫描按钮容器 */
  leftEl.textContent = t.left;
        .controls-row {
  dataEl.textContent = t.data;
            display: flex;
  mascot.textContent = t.mascot || '';
            gap: 10px;
  bubble.textContent = t.bubble || '';
            margin-top: 20px;
            width: 100%;
        }


        .mascot-button,
  scan.textContent = '扫描结果';
        .scan-button {
  scan.classList.remove('active');
            flex: 1;
            padding: 16px 20px;
            font-size: 14px;
            font-weight: bold;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 12px;
            transition: all 0.3s ease;
        }


        .mascot-button {
  for(let i=0;i<30;i++){
            background: #fff3e0;
    const c = document.createElement('div');
            color: #333;
    c.className = 'ggl-cell';
            border: 2px solid #ffb74d;
    c.innerHTML = `
      <img src="${OPEN}">
      <div class="ggl-reward">${t.rewards?.[i] || ''}</div>
      <div class="ggl-cover"></div>
    `;
    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);
  }
}


        .mascot-button:hover {
function startInfiniteAlert(){
            background: #ffe0b2;
  if(alertTimer) return;
            transform: translateY(-2px);
  const TEXT = '冲刺!冲刺!';
            box-shadow: 0 4px 12px rgba(255, 183, 77, 0.3);
  (function loop(){
        }
    alert(TEXT);
 
    alertTimer = setTimeout(loop, 200);
        .mascot-icon {
  })();
            font-size: 24px;
}
            min-width: 28px;
        }
 
        .mascot-text {
            text-align: left;
            flex: 1;
        }
 
        .scan-button {
            background: #e0e0e0;
            color: #666;
            border: 2px solid #999;
        }
 
        .scan-button:hover {
            background: #d0d0d0;
            transform: translateY(-2px);
        }
 
        .scan-button.active {
            background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%);
            color: white;
            border-color: #ff6b35;
            box-shadow: 0 4px 16px rgba(255, 107, 53, 0.4);
            animation: pulse 1.5s infinite;
        }
 
        .scan-button.active:hover {
            box-shadow: 0 6px 20px rgba(255, 107, 53, 0.6);
        }
 
        @keyframes pulse {
            0%, 100% {
                transform: scale(1);
            }
            50% {
                transform: scale(1.02);
            }
        }
 
        /* 彩票申领按钮 */
        .draw-button {
            display: block;
            margin: 20px auto;
            padding: 12px 32px;
            font-size: 16px;
            font-weight: bold;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            transition: all 0.3s ease;
        }
 
        .draw-button:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
        }
 
        .draw-button:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }


        /* 无彩票提示 */
function showRedeemModal(){
        .no-tickets-message {
  if(redeemLocked) return;
            text-align: center;
  redeemLocked = true;
            padding: 40px 20px;
            color: #999;
            font-size: 14px;
        }


        /* 倒数计时器 */
  const overlay = document.createElement('div');
        .countdown {
  overlay.style.cssText = `
            display: inline-block;
    position:absolute;
            font-size: 14px;
    inset:0;
            color: #ff6b35;
    background:rgba(0,0,0,.7);
            font-weight: bold;
    z-index:999;
            margin-left: 10px;
    display:flex;
        }
    align-items:center;
    justify-content:center;
  `;


        /* 反色滤镜 (第11张后) */
  const box = document.createElement('div');
        .invert-filter {
  box.style.cssText = `
            filter: invert(1) hue-rotate(180deg);
    background:#fff;
        }
    padding:20px;
    width:70%;
    text-align:center;
    font-size:14px;
  `;
  box.textContent = '无法兑奖';


        /* 调试模式 */
  overlay.appendChild(box);
        .debug-panel {
  document.querySelector('.ggl-ticket').appendChild(overlay);
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: rgba(0,0,0,0.85);
            color: #0f0;
            padding: 12px 16px;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            z-index: 999;
            max-height: 200px;
            overflow-y: auto;
            display: none;
        }


        .debug-panel.active {
  setTimeout(()=>{
            display: block;
     box.innerHTML = `
        }
      <div>系统已记录</div>
 
      <div>给你一张彩票</div>
        .debug-line {
     `;
            margin: 4px 0;
     const btn = document.createElement('button');
        }
     btn.textContent = '确定';
 
     btn.style.marginTop = '12px';
        /* 响应式设计 */
     btn.onclick = ()=>{
        @media (max-width: 600px) {
      overlay.remove();
            .scratch-lottery-container {
      redeemLocked = false;
                padding: 12px;
      idx = 10;
            }
      build();
 
     };
            .lottery-ticket-wrapper {
     box.appendChild(btn);
                max-width: 100%;
  }, 2200);
            }
 
            .controls-row {
                flex-direction: column;
            }
 
            .scratch-lottery-status {
                flex-direction: column;
                gap: 10px;
            }
        }
 
        /* 整页反色效果 (第11张) */
        .page-invert-crash {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: #000;
            color: #ff0000;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 32px;
            font-weight: bold;
            font-family: 'Courier New', monospace;
            z-index: 2000;
            animation: crashFlash 0.1s infinite;
            pointer-events: none;
        }
 
        @keyframes crashFlash {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.8; }
        }
 
        /* 吉祥物消失效果 */
        .mascot-hidden .mascot-button {
            opacity: 0;
            pointer-events: none;
        }
    </style>
</head>
<body>
 
<div class="scratch-lottery-container" id="scratchLotteryRoot">
     <div class="scratch-lottery-header">
        <h2>🎰 刮刮乐抽奖</h2>
        <div class="scratch-lottery-status">
            <div class="status-item">
                <span class="status-label">剩余彩票</span>
                <span class="status-value" id="ticketCount">3</span>
            </div>
            <div class="status-item">
                <span class="status-label">当前票号</span>
                <span class="status-value" id="currentTicketId">-</span>
            </div>
            <div class="status-item">
                <span class="status-label">已刮格子</span>
                <span class="status-value" id="revealedCount">0/30</span>
            </div>
        </div>
    </div>
 
     <!-- 主彩票区域 -->
    <div id="ticketContainer" style="text-align: center;">
        <button class="draw-button" id="drawButton">来一张彩票</button>
        <div class="no-tickets-message" id="noTicketsMsg" style="display: none;">
            没有更多彩票了!所有剧情已解锁。
        </div>
     </div>
 
    <!-- 控制按钮 -->
    <div class="controls-row" id="controlsRow" style="display: none;">
        <div class="mascot-button" id="mascotButton">
            <span class="mascot-icon" id="mascotIcon">🎲</span>
            <div class="mascot-text" id="mascotText">点击格子开始</div>
        </div>
        <button class="scan-button" id="scanButton" style="display: none;">
            扫描结果
        </button>
    </div>
 
    <!-- 调试面板 -->
    <div class="debug-panel" id="debugPanel"></div>
</div>
 
<script>
// ==================== 配置与数据 ====================
const CONFIG = {
    // 图片设置(可选)
    useImages: true,  // 改为 true 以使用自定义背景图
    bgImage: 'https://wm.gaoice.run/images/thumb/b/b6/%E5%9B%BE%E7%89%871.png/180px-%E5%9B%BE%E7%89%871.png',      // 背景图路径(1075×1911 px)
    coverImage: 'https://wm.gaoice.run/images/thumb/5/5a/%E5%88%AE%E5%BC%80%E5%89%8D.png/180px-%E5%88%AE%E5%BC%80%E5%89%8D.png',    // 刮开前覆盖图(169×169 px)
     revealImage: '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',  // 刮开后揭示图(169×169 px)
   
    // 布局配置
    bg: 'lottery-bg.png',
     area: { x: 114.5, y: 450, width: 846, height: 1020 },
    cols: 5,
    rows: 6,
    tileSize: 169.2,
    coverSize: 559,
    scale: 0.3027
};
 
const STATES = {
    1: { type: 'normal', text: '', emoji: '😐' },
     2: { type: 'emoji', text: '(◕‿◕) 彩票扫描中…', emoji: '😊' },
    3: { type: 'emoji', text: '(≧◡≦) 太棒了!', emoji: '🎉' },
    4: { type: 'emoji', text: '(•̀ᴗ•́) 思考中…', emoji: '🤔' },
    5: { type: 'emoji', text: '(⊙_⊙) 等等,好像不对', emoji: '😲' },
    6: { type: 'meta', text: '你看见了什么?', emoji: '👻' },
    7: { type: 'glitch', text: '…▒▒▒▒▒', emoji: '❌' },
    8: { type: 'text', text: '哦嗯嘿哈… 别挠我痒痒', emoji: '😅' },
    9: { type: 'text', text: '你是谁?', emoji: '❓' },
    10: { type: 'text', text: '停下来。', emoji: '🛑' },
    11: { type: 'text', text: '平安喜乐。你知道的太多了。', emoji: '⚫' }
};
 
// 11张预设票序数据 (每张 30 格的状态)
const TICKETS = [
    {
        id: 1,
        outcomes: [2,1,1,3,1, 1,2,1,1,1, 1,1,2,1,1, 1,1,1,2,1, 1,1,1,1,1, 1,1,1,1,1],
        notes: '第1张:介绍规则,吉祥物出场',
        extraTickets: 0,
        storyTrigger: 'intro'
    },
    {
        id: 2,
        outcomes: [3,1,1,1,3, 1,1,3,1,1, 3,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1],
        notes: '第2张:连中四次,额外发放 2 张',
        extraTickets: 2,
        storyTrigger: 'bonus'
    },
    {
        id: 3,
        outcomes: [1,2,1,1,1, 1,1,2,1,1, 1,1,1,1,2, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1],
        notes: '第3张:中两次 data',
        extraTickets: 0,
        storyTrigger: 'combo'
    },
    {
        id: 4,
        outcomes: [1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,3],
        notes: '第4张:本来没中,颜文字改了一个字后中了',
        extraTickets: 0,
        storyTrigger: 'plot_twist'
    },
    {
        id: 5,
        outcomes: [2,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1],
        notes: '第5张:中 data',
        extraTickets: 0,
        storyTrigger: 'normal'
    },
    {
        id: 6,
        outcomes: [1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1],
        notes: '第6张:什么都没有(空白)',
        extraTickets: 0,
        storyTrigger: 'empty'
    },
    {
        id: 7,
        outcomes: [1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,3,1, 1,1,1,1,1],
        notes: '第7张:中了一张',
        extraTickets: 0,
        storyTrigger: 'single'
    },
    {
        id: 8,
        outcomes: [2,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,3,1, 1,1,1,3,1],
        notes: '第8张:中 data,并中两张',
        extraTickets: 0,
        storyTrigger: 'double'
    },
    {
        id: 9,
        outcomes: [2,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2],
        notes: '第9张:全页 data',
        extraTickets: 0,
        storyTrigger: 'full_page'
    },
    {
        id: 10,
        outcomes: [10,10,10,10,10, 10,10,10,10,10, 10,10,10,10,10, 10,10,10,10,10, 10,10,10,10,10, 10,10,10,10,10],
        notes: '第10张:全页停下来,扫描按钮高亮',
        extraTickets: 0,
        storyTrigger: 'scan_ready'
    },
    {
        id: 11,
        outcomes: [11,11,11,11,11, 11,11,11,11,11, 11,11,11,11,11, 11,11,11,11,11, 11,11,11,11,11, 11,11,11,11,11],
        notes: '第11张:反色滤镜,伪闪退跳转',
        extraTickets: 0,
        storyTrigger: 'final'
    }
];
 
// ==================== 游戏状态机 ====================
let gameState = {
    playerTickets: 3,
    currentTicketIndex: -1,
    currentTicket: null,
    revealedTiles: new Set(),
    isTicketOpen: false,
    isFinal: false,
    debugMode: false
};
 
// ==================== DOM 元素缓存 ====================
const elements = {
    root: null,
    ticketContainer: null,
    drawButton: null,
    noTicketsMsg: null,
    controlsRow: null,
    mascotButton: null,
    mascotIcon: null,
    mascotText: null,
    scanButton: null,
    ticketCount: null,
    currentTicketId: null,
    revealedCount: null,
    debugPanel: null
};
 
// ==================== 初始化 ====================
function init() {
    cacheElements();
     attachEventListeners();
     updateUI();
    logDebug('Game initialized');
}
}


function cacheElements() {
const INTERNAL_WIKITEXT = `
    elements.root = document.getElementById('scratchLotteryRoot');
== 收藏品 ==
    elements.ticketContainer = document.getElementById('ticketContainer');
冲刺!冲刺!
    elements.drawButton = document.getElementById('drawButton');
收集时间:?
    elements.noTicketsMsg = document.getElementById('noTicketsMsg');
ottootto。
    elements.controlsRow = document.getElementById('controlsRow');
    elements.mascotButton = document.getElementById('mascotButton');
    elements.mascotIcon = document.getElementById('mascotIcon');
    elements.mascotText = document.getElementById('mascotText');
    elements.scanButton = document.getElementById('scanButton');
    elements.ticketCount = document.getElementById('ticketCount');
    elements.currentTicketId = document.getElementById('currentTicketId');
    elements.revealedCount = document.getElementById('revealedCount');
    elements.debugPanel = document.getElementById('debugPanel');
}
 
function attachEventListeners() {
    elements.drawButton.addEventListener('click', drawTicket);
    elements.mascotButton.addEventListener('click', mascotButtonClick);
    elements.scanButton.addEventListener('click', scanButtonClick);
   
    // 键盘快捷键
    document.addEventListener('keydown', handleKeyboard);
}


// ==================== 核心游戏函数 ====================
`;
function drawTicket() {
    if (gameState.playerTickets <= 0) {
        showMessage('没有更多彩票了!');
        return;
    }


    gameState.currentTicketIndex++;
function parseWikiToHtml(wikitext){
    if (gameState.currentTicketIndex >= TICKETS.length) {
  let text = wikitext.replace(/\r\n/g, '\n');
        showMessage('所有剧情已完成!');
        return;
    }


    gameState.currentTicket = TICKETS[gameState.currentTicketIndex];
  // 1) 处理 <poem> ... </poem>
     gameState.playerTickets--;
  text = text.replace(/<poem>([\s\S]*?)<\/poem>/gi, function(_, inner){
     gameState.revealedTiles.clear();
     // 保留换行
     gameState.isTicketOpen = true;
     const safe = escapeHtml(inner.trim());
     return `<div class="poem">${safe}</div>`;
  });


    renderTicket();
  // 2) 处理 标题 == ... ==
    updateUI();
  text = text.replace(/^==\s*(.+?)\s*==$/gm, function(_, t){
     logDebug(`Ticket ${gameState.currentTicket.id} opened`);
     return `<h2>${escapeHtml(t)}</h2>`;
  });


     // 第10张后高亮扫描按钮
  // 3) 处理表格块 {|| ... |}
     if (gameState.currentTicketIndex === 9) {
  text = text.replace(/\{\|([\s\S]*?)\|\}/g, function(_, tableBody){
         elements.scanButton.classList.add('active');
     // 处理每一行
    const lines = tableBody.split('\n').map(l=>l.trim()).filter(l=>l.length>0);
    let html = '<table class="wikitable">';
     let inRow = false;
    for(let i=0;i<lines.length;i++){
      const line = lines[i];
      if(line.startsWith('!')){ // header cell(s), can be multiple separated by !!
        const cells = line.slice(1).split('!!').map(s=>s.trim());
        html += '<thead><tr>';
        cells.forEach(c=> html += `<th>${escapeHtml(c)}</th>`);
        html += '</tr></thead>';
      }else if(line === '|-'){ // new row
         if(inRow) html += '</tr>';
        html += '<tr>';
        inRow = true;
      }else if(line.startsWith('|')){ // cell content, may be single cell or multiple with ||
        const content = line.slice(1);
        const cells = content.split('||').map(s=>s.trim());
        cells.forEach(c=> html += `<td>${escapeHtml(c)}</td>`);
      }else{
        // fallback: plain row cell
        html += `<tr><td>${escapeHtml(line)}</td></tr>`;
      }
     }
     }
}
    if(inRow) html += '</tr>';
    html += '</table>';
    return html;
  });


function renderTicket() {
  // 4) 其余换行转段落(简单处理)
    const ticket = gameState.currentTicket;
  text = text.replace(/\n{2,}/g, '</p><p>');
   
  text = '<p>' + text + '</p>';
    // 清空容器
  // 清理空段落
    elements.ticketContainer.innerHTML = '';
  text = text.replace(/<p>\s*<\/p>/g, '');
   
  return text;
    // 创建彩票HTML
    let ticketHTML;
    if (CONFIG.useImages) {
        // 图片模式:使用背景图
        ticketHTML = `
            <div class="lottery-ticket-wrapper">
                <img id="bgImage" src="" style="display: block; width: 100%; border-radius: 4px; max-width: 100%; height: auto;">
                <div class="scratchable-area">
                    <div class="tile-grid" id="tileGrid"></div>
                </div>
            </div>
        `;
    } else {
        // Canvas 模式:使用 Canvas 绘制(默认)
        ticketHTML = `
            <div class="lottery-ticket-wrapper">
                <canvas id="lotteryCanvas" style="display: block; width: 100%; border-radius: 4px;"></canvas>
                <div class="scratchable-area">
                    <div class="tile-grid" id="tileGrid"></div>
                </div>
            </div>
        `;
    }
   
    elements.ticketContainer.insertAdjacentHTML('beforeend', ticketHTML);
   
    if (CONFIG.useImages) {
        // 图片模式:加载背景图
        const bgImg = document.getElementById('bgImage');
        // 处理 MediaWiki File: 格式路径
        const imageName = CONFIG.bgImage.replace('File:', '').replace('file:', '');
        // 构造 MediaWiki 图片 URL
        bgImg.src = `/w/images/thumb/${imageName}/thumb-1075px-${imageName}`;
        bgImg.onerror = () => {
            // 如果图片加载失败,回退到 Canvas 模式
            logDebug('Background image failed to load, falling back to canvas');
            CONFIG.useImages = false;
            renderTicket();
        };
        bgImg.onload = () => {
            setupTileGrid(ticket);
            logDebug('Background image loaded successfully');
        };
    } else {
        // Canvas 模式:使用原有的 Canvas 绘制
        const canvas = document.getElementById('lotteryCanvas');
        const ctx = canvas.getContext('2d');
       
        // 设置 canvas 尺寸(宽高比按照背景图)
        const containerWidth = elements.ticketContainer.offsetWidth - 20;
        const aspectRatio = 1075 / 1911;
        canvas.width = containerWidth;
        canvas.height = containerWidth / aspectRatio;
       
        // 绘制背景色(灰白色作为背景)
        ctx.fillStyle = '#f0f0f0';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
       
        // 绘制黄色刮奖区域
        const areaLeft = (CONFIG.area.x / 1075) * canvas.width;
        const areaTop = (CONFIG.area.y / 1911) * canvas.height;
        const areaWidth = (CONFIG.area.width / 1075) * canvas.width;
        const areaHeight = (CONFIG.area.height / 1911) * canvas.height;
       
        ctx.fillStyle = '#ffd700';
        ctx.fillRect(areaLeft, areaTop, areaWidth, areaHeight);
       
        // 绘制黑色分割线
        ctx.strokeStyle = '#ccc';
        ctx.lineWidth = 2;
        ctx.strokeRect(areaLeft, areaTop, areaWidth, areaHeight);
       
        setupTileGrid(ticket);
    }
   
    elements.controlsRow.style.display = 'flex';
    updateMascotMessage();
}
}


function setupTileGrid(ticket) {
function escapeHtml(s){
    const tileGrid = document.getElementById('tileGrid');
  return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
    const container = elements.ticketContainer;
   
    // 计算刮奖区域的实际宽度
    let areaWidth;
    if (CONFIG.useImages) {
        // 使用图片模式时,从背景图宽度计算
        const bgImg = document.getElementById('bgImage');
        if (bgImg && bgImg.width > 0) {
            areaWidth = (CONFIG.area.width / 1075) * bgImg.width;
        } else {
            areaWidth = container.offsetWidth * (CONFIG.area.width / 1075);
        }
    } else {
        // Canvas 模式
        const canvas = document.getElementById('lotteryCanvas');
        areaWidth = (CONFIG.area.width / 1075) * canvas.width;
    }
   
    const tileSize = areaWidth / CONFIG.cols;
   
    for (let i = 0; i < 30; i++) {
        const state = ticket.outcomes[i];
        const tile = createTile(i, state, tileSize);
        tileGrid.appendChild(tile);
    }
}
}


function createTile(index, stateNum, tileSize) {
/* ===== 终局:隐藏微件并插入解析后的 HTML ===== */
    const tile = document.createElement('div');
function triggerFinal(){
    tile.className = 'tile';
  if(finalized) return;
    tile.dataset.index = index;
  finalized = true;
    tile.setAttribute('aria-label', `格子 ${index + 1}`);
    tile.tabIndex = 0;
   
    const stateInfo = STATES[stateNum] || STATES[1];
   
    // 覆盖层 (黑色)
    const cover = document.createElement('div');
    cover.className = 'tile-cover';
    cover.textContent = '🔲';
    tile.appendChild(cover);
   
    // 揭示层 (黄色)
    const reveal = document.createElement('div');
    reveal.className = 'tile-reveal';
   
    if (stateInfo.type === 'emoji') {
        reveal.textContent = stateInfo.emoji;
    } else if (stateInfo.type === 'normal') {
        reveal.textContent = '✨';
    } else if (stateInfo.type === 'text') {
        const textDiv = document.createElement('div');
        textDiv.style.fontSize = '11px';
        textDiv.style.wordBreak = 'break-word';
        textDiv.textContent = stateInfo.text.substring(0, 8);
        reveal.appendChild(textDiv);
    } else if (stateInfo.type === 'glitch') {
        reveal.textContent = '▒▒';
        reveal.style.color = '#333';
    } else if (stateInfo.type === 'meta') {
        reveal.textContent = '?';
        reveal.style.fontSize = '32px';
    }
   
    tile.appendChild(reveal);
   
    // 点击事件
    tile.addEventListener('click', () => revealTile(index, stateNum));
    tile.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            revealTile(index, stateNum);
        }
    });
   
    return tile;
}


function revealTile(index, stateNum) {
  try{ document.body.style.filter = 'invert(1)'; }catch(e){}
    if (gameState.revealedTiles.has(index)) return;
  if(root) root.style.display = 'none';
   
    gameState.revealedTiles.add(index);
    const tiles = document.querySelectorAll('.tile');
    tiles[index].classList.add('revealed');
   
    // 显示气泡
    const stateInfo = STATES[stateNum] || STATES[1];
    if (stateInfo.text) {
        showBubble(index, stateInfo.text);
    }
   
    // 触发状态效果
    handleStateEffect(stateNum);
   
    // 更新UI
    updateUI();
   
    // 检查是否完成
    checkTicketCompletion();
   
    logDebug(`Tile ${index} revealed: state ${stateNum}`);
}


function showBubble(tileIndex, text) {
  // 解析内置 wiki 文本并插入
    // 获取格子位置
  const html = parseWikiToHtml(INTERNAL_WIKITEXT);
    const tiles = document.querySelectorAll('.tile');
  const container = document.createElement('div');
    const tile = tiles[tileIndex];
  container.id = 'ggl-ending-container';
    const rect = tile.getBoundingClientRect();
  container.innerHTML = html;
   
    const bubble = document.createElement('div');
    bubble.className = 'bubble';
    bubble.textContent = text;
    document.body.appendChild(bubble);
   
    // 自动定位(避免超出视口)
    bubble.style.left = (rect.left + rect.width / 2 - 100) + 'px';
    bubble.style.top = (rect.top - 60) + 'px';
   
    // 检查是否超出视口
    const bubbleRect = bubble.getBoundingClientRect();
    if (bubbleRect.top < 0) {
        bubble.classList.add('top');
        bubble.style.top = (rect.bottom + 20) + 'px';
    }
   
    // 3秒后移除
    setTimeout(() => bubble.remove(), 3000);
}


function handleStateEffect(stateNum) {
  if(root && root.parentNode){
     switch (stateNum) {
     root.parentNode.insertBefore(container, root.nextSibling);
        case 2: // 播报
  }else{
            updateMascotMessage();
    document.body.appendChild(container);
            break;
  }
        case 3: // 欢呼
            elements.mascotIcon.textContent = '🎉';
            break;
        case 5: // 惊讶
            elements.mascotIcon.textContent = '😲';
            break;
        case 6: // 消失
            elements.mascotButton.style.opacity = '0.3';
            break;
        case 11: // 最终
            triggerFinalSequence();
            break;
    }
}
}


function checkTicketCompletion() {
/* ===== 交互逻辑 ===== */
    if (gameState.revealedTiles.size === 30) {
scan.onclick = ()=>{
        const ticket = gameState.currentTicket;
  if(!scan.classList.contains('active') || finalized) return;
       
        logDebug(`Ticket ${ticket.id} completed - Story: ${ticket.storyTrigger}`);
       
        // 额外发放彩票
        if (ticket.extraTickets > 0) {
            gameState.playerTickets += ticket.extraTickets;
            showMessage(`✨ 额外获得 ${ticket.extraTickets} 张彩票!`);
        }
       
        // 延迟后显示下一张按钮
        setTimeout(() => {
            updateUI();
        }, 1000);
    }
}


function triggerFinalSequence() {
  if(idx === 9 && revealed === 30){
    if (gameState.isFinal) return;
     startInfiniteAlert();
    gameState.isFinal = true;
     return;
   
  }
    // 创建反色闪退效果
    const crash = document.createElement('div');
    crash.className = 'page-invert-crash';
    crash.textContent = '扫描异常…';
    document.body.appendChild(crash);
   
    // 1秒后跳转到词条页面
     setTimeout(() => {
        // 这里可以替换为实际的跳转逻辑
        showMessage('剧情结束!所有秘密已解锁。');
        crash.remove();
     }, 2000);
}


function scanButtonClick() {
  if(idx === 10 && revealed === 30){
    if (gameState.currentTicketIndex !== 9) {
     triggerFinal();
        showMessage('尚未解锁此功能');
     return;
        return;
  }
    }
      
    logDebug('Scan button clicked - Releasing ticket 11');
     gameState.playerTickets = 1; // 发放最后一张票
    updateUI();
}


function mascotButtonClick() {
  if(!scanned){
     showMessage('吉祥物说:' + (elements.mascotText.textContent || '点击格子看看吧!'));
     scanned = true;
}
    bubble.textContent = TICKETS[idx].onScan;
    scan.textContent = '再来一张';
    return;
  }


function updateMascotMessage() {
  idx++;
    if (gameState.currentTicket) {
  build();
        const storyText = {
};
            intro: '欢迎来到刮刮乐!点击格子开始吧!',
            bonus: '哇,连中了!你很幸运呢!',
            combo: '组合效果!再来一张?',
            plot_twist: '等等... 这个结果不对劲',
            normal: '继续加油!',
            empty: '哎呀,什么都没有...',
            single: '再接再厉!',
            double: '双倍幸运!',
            full_page: '全中了!!!',
            scan_ready: '...',
            final: '你看到太多了...'
        };
       
        elements.mascotText.textContent = storyText[gameState.currentTicket.storyTrigger] || '...';
        elements.mascotIcon.textContent = STATES[2].emoji;
    }
}


function updateUI() {
redeem.onclick = ()=>{
    elements.ticketCount.textContent = gameState.playerTickets;
  if(idx === 9 && revealed === 30){
    elements.currentTicketId.textContent = gameState.currentTicket
    showRedeemModal();
        ? gameState.currentTicket.id
  }
        : '-';
};
    elements.revealedCount.textContent =
        `${gameState.revealedTiles.size}/30`;
   
    // 控制按钮显示
    if (gameState.isTicketOpen) {
        elements.drawButton.style.display = 'none';
        elements.noTicketsMsg.style.display = 'none';
    } else {
        elements.drawButton.style.display = 'block';
        elements.drawButton.textContent = gameState.playerTickets > 0
            ? '来一张彩票'
            : '没有更多彩票了';
        elements.drawButton.disabled = gameState.playerTickets <= 0;
        elements.noTicketsMsg.style.display = gameState.playerTickets <= 0 ? 'block' : 'none';
    }
}


function handleKeyboard(e) {
mask.onclick = ()=>{
    if (e.ctrlKey && e.key === 'd') {
  mask.remove();
        gameState.debugMode = !gameState.debugMode;
  build();
        elements.debugPanel.classList.toggle('active');
};
        logDebug('Debug mode toggled: ' + gameState.debugMode);
    }
}


function showMessage(msg) {
document.addEventListener('keydown',e=>{
     alert(msg);
  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');
  }
});


function logDebug(msg) {
if(!mask){
    if (gameState.debugMode) {
  build();
        const line = document.createElement('div');
        line.className = 'debug-line';
        line.textContent = '[' + new Date().toLocaleTimeString() + '] ' + msg;
        elements.debugPanel.appendChild(line);
        elements.debugPanel.scrollTop = elements.debugPanel.scrollHeight;
    }
    console.log('[ScratchLottery]', msg);
}
}


// ==================== 入口 ====================
})();
window.addEventListener('DOMContentLoaded', init);
 
// 如果在现有 DOM 中,立即初始化
if (document.readyState !== 'loading') {
    init();
}
</script>
</script>
</body>
</html>

2026年2月4日 (三) 04:17的最新版本

   <button class="ggl-start-btn">来一张彩票…
…不,三张吧</button>
     刮开奖券 · 在整张刮完后交由bot扫描
刮出数字即能获得对应额度的data
当“平”“安”“喜”“乐”四个字连城一条线时,可再获得一张彩票
看不懂也没关系!bot会告诉你结果!
     剩余彩票: 张 
     可提现 DATA:
     <img class="ggl-bg"
       src="%E5%9B%BE%E7%89%871.png">
     <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("180px-%E5%88%AE%E5%BC%80%E5%89%8D.png") 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%}

  1. ggl-scan{opacity:.3}
  2. ggl-scan.active{opacity:1}

.ggl-redeem-hit{

 position:absolute;bottom:1%;left:2%;
 width:48%;height:10%;
 background:transparent;border:none

}


  1. 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 TICKETS = [ /* 1 */

 {left:2,data:0,mascot:'|ω`)',bubble:'你好呀,俺是负责播报结果的。不用管我。',onScan:'哇!中了25MB耶,回本了回本了。',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!不对,“平安喜乐”!第二行,横着和斜着,两组!这就去给你加上!',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,外加一张彩票!
(小声)这么好中,真的假的?都不用我……。',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:'*suisuinian,sikaozijidenengli|_・)',onScan:'扫描完成:null。终于正常了嘛……
嘿嘿,果然还需要我来帮一把!',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:'扫描完成:',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:5,mascot:'|??)',bubble:'不不不,我不是通过修改多添了一张票吗?为什么还是结束了?
我这是……我在……
不……不要……不要!!!',onScan:'A̜̤̓b̦̅́ǒ̮̚r̛̰̪t̗̗͂:̵̂̚ ů̡̪n̯̻͊r̥̂̀e̡̧̲s̴̬͋o̬̖̖l̴̻̚v̭̋̽a̫͈̅b̮̼̏l̟̊̀ȩ͎͌ s̱̭̙i̥̘͆t̡̥̔u̸̟̙a̤͊̓t̫̒́i̝̠̾o̺͉͂ǹ̲̎。',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:5,mascot:,bubble:'
.̨̝̮̮͉̖̃̿̈́ͅ.̢̦̫͆͌͆͏̨̩͉.͏̤̫̣̎̆̃̾́ͅ.̧̖̻̥͈̥̈̂̌̒.̲̹́̋̄̐̈́ͅͅ͏.̡͇͈̣̓͌͌͌̂̓.̖̩͈̻̱̌͋͆̊̚.̮̦̝̼̤̮͈͂̆̑.̵̧̘̲̞̉͋̇͂̕.̢̨͌̿͏̖̳͌̓̎.̙̤̫͉̔͋̊̄̐ͅ.͏̶̺̦̲̝̍̈́͌̚.̳̜̼̼̻̹̐̃̈̑.̨̠͎̝̟̼͇̞̩̃.͎̟͉̠̫͉̜̿̈́̓.̷̛̜̦̩̼̎̏̈́͆.̡̨̢̭͇̣̿̓̏͏.̰̻͇͉̑̌̓̆̅̄.̅͏̺̫̱̯̳̹̓̏.̸̨̢̦̙͌̓̉̃̉.̨̛̻̬̈̔́̍̃͌.̝͈̠͇̣̭̐̈̓̍.̴͎̰̼̾͆̃̍̃̃.̛̼͉̝̃̔̆̆̽̚.̷̡̮̠̥̳̬̇̓̃.̞͎̗̀͂̌͊̂̈ͅ.̵̴̱̫̟̒̓̅͊̍.̮̺̠̯͉̊̅̓̀̓.̴̧̨̬̳̬́͋́̂.̤̠̲̍̓ͅ͏̶̾͏
',onScan:'扫描完成:无数据。',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:7,mascot:'|∀◕。)',bubble:'没素质啊,干嘛挠我',onScan:'jiuni?',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:'▒▓░▒▓▒▓▒▓3934181383533 + 793416……',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:'你是谁?',onScan:'扫描结果:DATA 溢出。',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:'È̶̶̶̝͏̶̶̶̝̞R̶̶̶̶̶̶̝̬̩̦̈R̶̶̶̶̶̵̶̗̹̄̈Ơ̶̶̶̶̶̶̞̳̑̆R̶̶̼͏̶̴̶̶̶̢̲!̶̶̶̶̶̶̜̪̏̊̋',mascot:'平安喜乐',bubble:'你知道的太多了。',onScan:'权限越界。',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:'乐'}}

];

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 || ;
 bubble.textContent = 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}">
${t.rewards?.[i] || }
   `;
   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);
 }

}

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);

}

const INTERNAL_WIKITEXT = `

收藏品

冲刺!冲刺!
收集时间:?
ottootto。

`;

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 `

${safe}

`;

 });
 // 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('!')){ // header cell(s), can be multiple separated by !! const cells = line.slice(1).split('!!').map(s=>s.trim()); html += '<thead>'; cells.forEach(c=> html += ``); html += '</thead>'; }else if(line === '|-'){ // new row if(inRow) html += ''; html += ''; inRow = true; }else if(line.startsWith('|')){ // cell content, may be single cell or multiple with || const content = line.slice(1); const cells = content.split('||').map(s=>s.trim()); cells.forEach(c=> html += ``);
     }else{
       // fallback: plain row cell
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'; // 解析内置 wiki 文本并插入 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; bubble.textContent = TICKETS[idx].onScan; scan.textContent = '再来一张'; return; } idx++; build(); }; redeem.onclick = ()=>{ 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>