From a13b2290833f635453622ed330cc3895950ffcdb Mon Sep 17 00:00:00 2001
From: Mistivia <i@mistivia.com>
Date: Fri, 21 Feb 2025 23:04:36 +0800
Subject: add banlist

---
 src/card_db.js                    |  19 ++++
 src/components/card_thumb.svelte  |  77 ++++++++++++---
 src/components/main_panel.svelte  |  25 ++++-
 src/components/right_panel.svelte |   6 +-
 src/deck.js                       |  43 +++++++--
 src/ocg_banlist.json              | 195 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 338 insertions(+), 27 deletions(-)
 create mode 100644 src/ocg_banlist.json

diff --git a/src/card_db.js b/src/card_db.js
index b9b991f..5660ff3 100644
--- a/src/card_db.js
+++ b/src/card_db.js
@@ -1,5 +1,23 @@
+import ocgBanList from "./ocg_banlist.json";
+
 let cardDb = {};
 let altId = {};
+let banList = {
+    none: {
+        ban: [],
+        limit: [],
+        semiLimit: [],
+    },
+    ocg: ocgBanList,
+};
+
+function cardLimit(id, env) {
+    let lst = banList[env];
+    if (lst.ban.includes(id)) return 0;
+    if (lst.limit.includes(id)) return 1;
+    if (lst.semiLimit.includes(id)) return 2;
+    return 3;
+}
 
 function setCardDb(d) {
     cardDb = d;
@@ -22,4 +40,5 @@ export {
     setCardDb,
     getAltId,
     setAltId,
+    cardLimit,
 };
diff --git a/src/components/card_thumb.svelte b/src/components/card_thumb.svelte
index 8e701ea..e68a37e 100644
--- a/src/components/card_thumb.svelte
+++ b/src/components/card_thumb.svelte
@@ -1,9 +1,8 @@
 <script lang="js">
-
     import { setLeftPanelCard } from '../left_panel';
     import { cardImageUrl } from '../utils';
 
-    let {id, area, idx} = $props();
+    let {id, area, idx, limitNum} = $props();
 
     function onhover() {
         setLeftPanelCard(id); 
@@ -12,22 +11,74 @@
     function onDragStart(e) {
         e.dataTransfer.setData('text', JSON.stringify({id, area, idx}))
     }
-
 </script>
 
 {#if id}
-    <img
-        style="margin:2px;"
-        draggable="true"
-        onmouseover={onhover}
-        onfocus={onhover}
-        ondragstart={onDragStart}
-        height="100%"
-        src={cardImageUrl(id)}
-        alt="yugioh card {id}"
-    />
+   <img
+       style="margin:2px;"
+       draggable="true"
+       onmouseover={onhover}
+       onfocus={onhover}
+       ondragstart={onDragStart}
+       height="100%"
+       src={cardImageUrl(id)}
+       alt="yugioh card {id}"
+   />
+   {#if limitNum === 1 || limitNum == 2}
+       <div class="overlay">{limitNum}</div>
+   {:else if limitNum === 0}
+       <div class="ban-overlay"></div>
+   {/if}
 {/if}
 
 <style>
+    .overlay {
+        position: absolute;
+        top: 0;
+        left: 0;
+        border: 3px solid red;
+        border-radius: 50%;
+        background-color: black;
+        width: 20px;
+        height: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-weight: bold;
+        color: yellow;
+        font-size: 15px;
+        font-family: Arial, sans-serif;
+        box-sizing: border-box;
+        pointer-events: none;
+    }
+    
+    .ban-overlay {
+        position: absolute;
+        top: 0;
+        left: 0;
+        border: 3px solid red;
+        border-radius: 50%;
+        background-color: black;
+        width: 20px;
+        height: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-weight: bold;
+        color: yellow;
+        font-size: 15px;
+        font-family: Arial, sans-serif;
+        box-sizing: border-box;
+        pointer-events: none;
+    }
 
+    .ban-overlay::after {
+        content: '';
+        width: 15px;
+        height: 3px;
+        background-color: red;
+        transform: rotate(45deg);
+        position: absolute;
+        pointer-events: none;
+    }
 </style>
diff --git a/src/components/main_panel.svelte b/src/components/main_panel.svelte
index 2db7a34..1c55d49 100644
--- a/src/components/main_panel.svelte
+++ b/src/components/main_panel.svelte
@@ -1,6 +1,7 @@
 <script lang="js">
     import CardThumb from './card_thumb.svelte';
-    import { deck, setDeck, deckOps } from '../deck';
+    import { deck, setDeck, deckOps, format, setFormat } from '../deck';
+    import { cardLimit } from '../card_db';
     import {
         parseYdk,
         genYdk,
@@ -74,6 +75,8 @@
     }
 
 
+
+
 </script>
 
 <input bind:this={fileInput} style="display:none;" onchange={loadDeck} type="file" class="file-input" accept=".ydk" />
@@ -84,6 +87,11 @@
         <button class="btn" onclick={saveDeck}>保存</button>
         <button class="btn" onclick={copyDeck}>复制到剪贴板</button>
         <button class="btn" onclick={shareDeck}>分享</button>
+        <select bind:value={$format} class="select-format" id="format" onchange={()=>setFormat($format)}>
+            <option value="none">无禁限</option>
+            <option value="ocg">OCG</option>
+        </select>
+
     </div>
     <div class="deck-section">
         <div class="deck-group">
@@ -91,7 +99,7 @@
             <div role="region" ondragover={(e)=>e.preventDefault()} ondrop={(e)=>onDrop("main", e, -1)} class="card-grid main-deck">
                 {#each $deck.main as card, i}
                     <div class="card-grid-thumb" role="region" ondragover={(e)=>e.preventDefault()} ondrop={(e)=>onDrop("main", e, i)}>
-                        <CardThumb id={card} idx={i} area="main" />
+                        <CardThumb id={card} idx={i} area="main" limitNum={cardLimit(card, $format)} />
                     </div>
                 {/each}
             </div>
@@ -101,7 +109,7 @@
             <div role="region" ondragover={(e)=>e.preventDefault()} ondrop={(e)=>onDrop("extra", e, -1)} class="card-grid extra-deck">
                 {#each $deck.extra as card, i}
                     <div class="card-grid-thumb" role="region" ondragover={(e)=>e.preventDefault()} ondrop={(e)=>onDrop("extra", e, i)}>
-                        <CardThumb id={card} idx={i} area="extra" />
+                        <CardThumb id={card} idx={i} area="extra" limitNum={cardLimit(card, $format)} />
                     </div>
                 {/each}
             </div>
@@ -111,7 +119,7 @@
             <div role="region" ondragover={(e)=>e.preventDefault()} ondrop={(e)=>onDrop("side", e, -1)} class="card-grid side-deck">
                 {#each $deck.side as card, i}
                     <div class="card-grid-thumb" role="region" ondragover={(e)=>e.preventDefault()} ondrop={(e)=>onDrop("side", e, i)}>
-                        <CardThumb id={card} idx={i} area="side" />
+                        <CardThumb id={card} idx={i} area="side" limitNum={cardLimit(card, $format)} />
                     </div>
                 {/each}
             </div>
@@ -142,6 +150,14 @@
     cursor: pointer;
 }
 
+
+.select-format {
+    padding: 8px 8px;
+    margin-right: 10px;
+    cursor: pointer;
+    font-size: 1.1em;
+}
+
 .deck-group {
     margin-bottom: 30px;
 }
@@ -163,6 +179,7 @@
 }
 
 .card-grid-thumb {
+    position: relative;
     aspect-ratio: 1/1.4;
     border-radius: 5px;
 }
diff --git a/src/components/right_panel.svelte b/src/components/right_panel.svelte
index 816687e..9863d97 100644
--- a/src/components/right_panel.svelte
+++ b/src/components/right_panel.svelte
@@ -1,7 +1,8 @@
 <script lang="js">
     import CardThumb from './card_thumb.svelte';
     import { changeInput, showingCards, onPrevPage, onNextPage } from '../search'
-    import { deckOps } from '../deck';
+    import { deckOps, format } from '../deck';
+    import { cardLimit } from '../card_db';
 
     function onChange(event) {
         changeInput(event.target.value);
@@ -24,7 +25,7 @@
            {#each $showingCards as card}
                <div class="card-item">
                    <div class="card-thumbnail">
-                       <CardThumb id={card.id} idx={-1} area="search" />
+                       <CardThumb id={card.id} idx={-1} area="search" limitNum={cardLimit(card.id, $format)} />
                    </div>
                    <span>{card.name}</span>
                </div>
@@ -87,6 +88,7 @@
 }
 
 .card-thumbnail {
+    position: relative;
     width: 50px;
     height: 70px;
     background-color: #eee;
diff --git a/src/deck.js b/src/deck.js
index 285320b..7812128 100644
--- a/src/deck.js
+++ b/src/deck.js
@@ -1,11 +1,15 @@
 import { writable } from "svelte/store";
 import { parseYdke } from './utils';
-import { getCardDb, getAltId } from './card_db';
+import { getCardDb, getAltId, cardLimit } from './card_db';
 
 let deck = writable({main: [], extra: [], side: []});
 let deckState = {main: [], extra: [], side: []};
 
-function sanitizeDeck(deck) {
+let defaultFormat = 'none';
+let format = writable(defaultFormat);
+let formatState = defaultFormat;
+
+function sanitizeDeck(cardCnt, deck) {
     let cardDb = getCardDb();
     let altId = getAltId();
     let ret = [];
@@ -13,17 +17,26 @@ function sanitizeDeck(deck) {
         if (altId[id] !== undefined) {
             id = altId[id];
         }
-        if (cardDb[id] !== undefined) {
-            ret.push(id);
+        if (cardDb[id] === undefined) {
+            continue;
+        }
+        if (!cardCnt.has(id)) {
+            cardCnt.set(id, 0);
         }
+        if (cardCnt.get(id) >= cardLimit(id, formatState)) {
+            continue;
+        }
+        ret.push(id);
+        cardCnt.set(id, cardCnt.get(id) + 1);
     }
     return ret;
 }
 
 function setDeck(d) {
-    d.main = sanitizeDeck(d.main);
-    d.side = sanitizeDeck(d.side);
-    d.extra = sanitizeDeck(d.extra);
+    let cardCnt = new Map();
+    d.main = sanitizeDeck(cardCnt, d.main);
+    d.side = sanitizeDeck(cardCnt, d.side);
+    d.extra = sanitizeDeck(cardCnt, d.extra);
     deckState = d;
     deck.set(d);
     localStorage.setItem('cachedDeck', JSON.stringify(d));
@@ -82,7 +95,6 @@ let deckOps = {
     },
     "add2main": (id, targetIdx) => {
         let cardDb = getCardDb();
-        console.log(targetIdx);
         if (cardDb[id].isExtra) return;
         let d = deckState;
         if (canAdd(d, id)) {
@@ -117,6 +129,10 @@ function initDeck() {
             return;
         }
     }
+    let cachedFormat = localStorage.getItem('format');
+    if (cachedFormat !== null) {
+        setFormat(cachedFormat);
+    }
     let cachedDeck = localStorage.getItem('cachedDeck');
     if (cachedDeck !== null) {
         cachedDeck = JSON.parse(cachedDeck); 
@@ -125,8 +141,19 @@ function initDeck() {
     }
 }
 
+function setFormat(newFormat) {
+    if (newFormat === 'none' || newFormat === 'ocg') {
+        localStorage.setItem('format', newFormat);
+        formatState = newFormat;
+        format.set(newFormat);
+        setDeck(deckState);
+    }
+}
+
 export {
     deck,
+    format,
+    setFormat,
     setDeck,
     deckOps,
     initDeck,
diff --git a/src/ocg_banlist.json b/src/ocg_banlist.json
new file mode 100644
index 0000000..2763143
--- /dev/null
+++ b/src/ocg_banlist.json
@@ -0,0 +1,195 @@
+{
+    "ban": [
+        "95727991",
+        "69015963",
+        "11384280",
+        "79571449",
+        "55144522",
+        "80604091",
+        "85602018",
+        "17375316",
+        "44763025",
+        "42829885",
+        "42703248",
+        "74191942",
+        "61740673",
+        "70828912",
+        "57953380",
+        "60682203",
+        "91869203",
+        "78706415",
+        "63789924",
+        "93016201",
+        "28566710",
+        "41482598",
+        "64697231",
+        "79875176",
+        "46411259",
+        "35059553",
+        "34206604",
+        "34906152",
+        "69243953",
+        "44910027",
+        "23557835",
+        "3280747",
+        "27174286",
+        "32723153",
+        "31423101",
+        "15341821",
+        "17178486",
+        "73356503",
+        "75732622",
+        "14702066",
+        "20663556",
+        "96782886",
+        "63101919",
+        "23558733",
+        "93369354",
+        "57421866",
+        "8903700",
+        "88071625",
+        "5851097",
+        "16923472",
+        "34086406",
+        "54719828",
+        "51858306",
+        "21044178",
+        "54447022",
+        "17412721",
+        "63504681",
+        "77679716",
+        "34945480",
+        "58820923",
+        "52653092",
+        "62242678",
+        "27552504",
+        "9929398",
+        "90809975",
+        "85115440",
+        "88581108",
+        "50588353",
+        "3679218",
+        "39064822",
+        "22593417",
+        "86148577",
+        "59537380",
+        "76375976",
+        "83152482",
+        "70369116",
+        "85243784",
+        "3040496",
+        "2563463",
+        "92731385",
+        "27381364",
+        "25926710",
+        "62320425",
+        "32909498"
+    ],
+    "limit": [
+        "8124921",
+        "44519536",
+        "70903634",
+        "7902349",
+        "33396948",
+        "18144506",
+        "72892473",
+        "83764718",
+        "19613556",
+        "34124316",
+        "81439173",
+        "32807846",
+        "73628505",
+        "90846359",
+        "82732705",
+        "23701465",
+        "75500286",
+        "1845204",
+        "1475311",
+        "23516703",
+        "17266660",
+        "53334471",
+        "2295440",
+        "27970830",
+        "6602300",
+        "93600443",
+        "90953320",
+        "33782437",
+        "75433814",
+        "20292186",
+        "90361010",
+        "7394770",
+        "38814750",
+        "74586817",
+        "94689206",
+        "78872731",
+        "48905153",
+        "76794549",
+        "73468603",
+        "21076084",
+        "24207889",
+        "24094258",
+        "23002292",
+        "52340444",
+        "65681983",
+        "37818794",
+        "84211599",
+        "44362883",
+        "92107604",
+        "76145933",
+        "13533678",
+        "74078255",
+        "572850",
+        "37961969",
+        "73956664",
+        "36521307",
+        "15443125",
+        "77103950",
+        "63542003",
+        "99937011",
+        "33854624",
+        "6637331",
+        "32731036",
+        "68304193",
+        "72656408",
+        "4928565",
+        "71832012",
+        "21347668",
+        "61292243",
+        "85106525",
+        "72270339",
+        "9674034",
+        "29301450",
+        "90241276",
+        "91810826",
+        "30336082",
+        "80453041",
+        "60764609",
+        "98567237",
+        "34022970"
+    ],
+    "semiLimit": [
+        "33508719",
+        "45986603",
+        "48130397",
+        "67723438",
+        "23434538",
+        "81275020",
+        "17330916",
+        "35261759",
+        "46060017",
+        "35726888",
+        "11110587",
+        "12289247",
+        "21377582",
+        "24224830",
+        "49238328",
+        "52947044",
+        "91800273",
+        "65734501",
+        "92714517",
+        "2526224",
+        "93729896",
+        "7477101"
+    ]
+}
+ 
-- 
cgit v1.0

