微件:GGLScratchGame:修订间差异

来自Limbo Wiki Mirror
Gaoice留言 | 贡献
无编辑摘要
标签(旧)WikiEditor
Gaoice留言 | 贡献
无编辑摘要
标签(旧)WikiEditor
第11行: 第11行:
       点击灰色区域揭示内容,全部揭示后才能扫描。
       点击灰色区域揭示内容,全部揭示后才能扫描。
     </div>
     </div>
     <div class="ggl-tickets-left">
     <div class="ggl-remaining">
       剩余彩票:<span id="ggl-ticket-count">3</span>
       剩余彩票:<span id="ggl-ticket-left"></span>
     </div>
     </div>
   </div>
   </div>
第53行: 第53行:
/* 顶部 */
/* 顶部 */
.ggl-top {
.ggl-top {
   margin-bottom: 8px;
   position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 30%;
  padding: 10px;
  box-sizing: border-box;
}
}
.ggl-rules {
.ggl-rules {
   font-size: 12px;
   font-size: 14px;
   opacity: .8;
   opacity: .8;
}
}
.ggl-remaining {
  margin-top: 6px;
  font-size: 16px;
  font-weight: bold;
}
.ggl-tickets-left {
.ggl-tickets-left {
   font-size: 14px;
   font-size: 14px;
第185行: 第199行:
(function () {
(function () {


  /********************
  * 全局状态
  ********************/
  const gameState = {
    totalTickets: 11,
    currentTicket: 1,
    totalCells: 30,
    revealedCells: 0,
    started: false,
    data: 0
  };
  /********************
  * DOM
  ********************/
   const grid = document.querySelector('.ggl-grid');
   const grid = document.querySelector('.ggl-grid');
   const bubble = document.querySelector('.ggl-bubble');
   const bubble = document.querySelector('.ggl-bubble');
   const mascot = document.querySelector('.ggl-mascot');
   const mascot = document.querySelector('.ggl-mascot');
   const scanBtn = document.getElementById('ggl-scan');
   const scanBtn = document.getElementById('ggl-scan');
  const overlay = document.querySelector('.ggl-overlay');
  const ticketCountEl = document.getElementById('ggl-ticket-count');


   let currentTicket = 0;
   const ticketLeftEl = document.getElementById('ggl-ticket-left');
   let revealed = 0;
   const startMask = document.getElementById('ggl-start-mask');
  let ticketsLeft = 3;


   /* 11 张彩票的数据(示例,可继续细填) */
  mascot.style.color = '#000';
   const TICKETS = [
 
     {
   /********************
       mascot: "",
  * 彩票剧情表(核心)
       bubble: "第一次通常会中点 Data。",
  ********************/
       prizes: { 12: "Data" }
   const TICKETS = {
     1: {
       mascot: '(^▽^)',
       text: '欢迎,先来三张试试吧。',
       rewards: ['DATA', 'EMPTY', 'EMPTY']
     },
     },
     {
     2: {
       mascot: "(^▽^)",
       mascot: '(ノ◕ヮ◕)ノ',
       bubble: "连着点四个字会有奖励。",
       text: '四个字可以连在一起。',
       prizes: { 3: "Data", 4: "Data", 5: "Data", 6: "Data" }
       rewards: ['DATA','DATA','DATA','DATA']
     },
     },
     {
     3: {
       mascot: "(ノ◕ヮ◕)ノ",
       mascot: '(・∀・)',
       bubble: "中奖了!Data 2MB。",
       text: '中了刮刮乐!+1 Data',
       prizes: { 10: "刮刮乐 +1", 15: "Data 2MB" }
       rewards: ['DATA']
     },
     },
     {
     4: {
       mascot: "(・_・)",
       mascot: '(・_・)',
       bubble: "……刚才那样不太对。",
       text: '什么都没中。',
       prizes: {}
       rewards: []
     },
     },
     {
     5: {
       mascot: "(;゚Д゚)",
       mascot: '(;゚Д゚)',
       bubble: "好像哪里不对。",
       text: '不对劲……又中了 Data。',
       prizes: { 8: "Data" }
       rewards: ['DATA']
     },
     },
     {
     6: {
       mascot: "",
       mascot: '',
       bubble: "什么都没有。",
       text: '什么都没有。',
       prizes: {}
       rewards: []
     },
     },
     {
     7: {
       mascot: "...",
       mascot: '...',
       bubble: "▒▒▒▒▒▒▒",
       text: '▒▓░▒▓░▒▓',
       prizes: { 20: "刮刮乐 +1" }
       rewards: ['DATA']
     },
     },
     {
     8: {
       mascot: "",
       mascot: '(^▽^)',
       bubble: "哦嗯嘿哈……别挠我痒痒",
       text: '中了两张 Data!',
       prizes: { 1: "Data", 2: "刮刮乐 +2" }
       rewards: ['DATA','DATA']
     },
     },
     {
     9: {
       mascot: "",
       mascot: '(・_・)',
       bubble: "你是谁?",
       text: '……全部都是 Data?',
       prizes: "ALL_DATA"
       rewards: Array(30).fill('DATA')
     },
     },
     {
     10: {
       mascot: "",
       mascot: '(;゚Д゚)',
       bubble: "停下来。",
       text: '停下来。',
      rewards: [],
       lock: true
       lock: true
     },
     },
     {
     11: {
       mascot: "平安喜乐",
       mascot: '平安喜乐',
       bubble: "你知道的太多了。",
       text: '你知道的太多了。',
      rewards: [],
       end: true
       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 || '';
  }


   function renderTicket() {
  /********************
     grid.innerHTML = "";
  * 构建 30 格
     revealed = 0;
  ********************/
     scanBtn.classList.remove("active");
   function buildGrid(ticket) {
     grid.innerHTML = '';
     gameState.revealedCells = 0;
     scanBtn.classList.remove('active');


     const t = TICKETS[currentTicket];
     const rewardMap = buildRewardMap(ticket);
     mascot.textContent = t.mascot || "";
     const locked = TICKETS[ticket].lock;
    bubble.textContent = t.bubble || "";
    ticketCountEl.textContent = ticketsLeft;


     for (let i = 0; i < 30; i++) {
     for (let i = 0; i < 30; i++) {
       const cell = document.createElement('div');
       const cell = document.createElement('div');
       cell.className = "ggl-cell";
       cell.className = 'ggl-cell';
      cell.dataset.revealed = "0";
 
      const prizeText =
        t.prizes === "ALL_DATA" ? "Data" :
        t.prizes[i] || "";


       cell.innerHTML = `
       cell.innerHTML = `
         <img class="ggl-reveal"
         <img src="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">
            src="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">
         <div class="ggl-reward">${rewardMap[i] === 'DATA' ? 'DATA' : ''}</div>
         <div class="ggl-prize">${prizeText}</div>
         <div class="ggl-cover"></div>
         <img class="ggl-cover"
            src="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">
       `;
       `;


       cell.addEventListener('click', () => {
       const cover = cell.querySelector('.ggl-cover');
        if (cell.dataset.revealed === "1") return;
 
        if (t.lock) return;
      if (!locked) {
        cover.addEventListener('click', () => {
          if (cell.dataset.done) return;
          cell.dataset.done = '1';
          cover.style.opacity = '0';
          gameState.revealedCells++;


        cell.dataset.revealed = "1";
          if (rewardMap[i] === 'DATA') {
        cell.querySelector('.ggl-cover').style.display = "none";
            gameState.data++;
        revealed++;
          }


        if (revealed === 30) {
          if (gameState.revealedCells >= gameState.totalCells) {
          scanBtn.classList.add("active");
            scanBtn.classList.add('active');
          bubble.textContent = "已全部揭示,可以扫描。";
            bubble.textContent = '可以扫描了。';
         }
          }
       });
         });
       }


       grid.appendChild(cell);
       grid.appendChild(cell);
第300行: 第356行:
   }
   }


  /********************
  * 下一张彩票
  ********************/
  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', () => {
   scanBtn.addEventListener('click', () => {
     if (!scanBtn.classList.contains("active")) return;
     if (!scanBtn.classList.contains('active')) return;


     if (TICKETS[currentTicket].end) {
     bubble.textContent = '扫描中……';
      document.body.style.filter = "invert(1)";
      bubble.style.background = "#000";
      bubble.style.color = "red";
      setTimeout(() => {
        location.href = "/index.php?title=六世恶言之一";
      }, 1500);
      return;
    }


     currentTicket++;
     setTimeout(() => {
    if (currentTicket < TICKETS.length) {
      if (TICKETS[gameState.currentTicket].end) {
       renderTicket();
        location.href = '/index.php?title=六世恶言之一';
     }
       } else {
        nextTicket();
      }
     }, 800);
   });
   });


   document.querySelector('.ggl-start-btn').addEventListener('click', () => {
   /********************
    overlay.style.display = "none";
  * 初始化遮罩
     renderTicket();
  ********************/
   });
  if (startMask) {
    startMask.addEventListener('click', () => {
      startMask.remove();
      gameState.started = true;
      updateTopUI();
      updateMascot(1);
      buildGrid(1);
     });
   } else {
    updateTopUI();
    updateMascot(1);
    buildGrid(1);
  }


})();
})();
</script>
</script>

2026年2月1日 (日) 19:35的版本

   <button class="ggl-start-btn">开始抽奖</button>
     点击灰色区域揭示内容,全部揭示后才能扫描。
     剩余彩票:
   <img class="ggl-bg"
        src="180px-%E5%9B%BE%E7%89%871.png">
     <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%;

}

  1. ggl-scan {
 opacity: .3;

}

  1. 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="180px-%E5%88%AE%E5%BC%80%E5%90%8E.jpg">
${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>