1
0
mirror of https://github.com/tcgdex/cards-database.git synced 2025-08-15 01:41:59 +00:00

Compare commits

..

38 Commits

Author SHA1 Message Date
TCGdexBOT
18baec5856 test 2025-05-07 17:01:32 +02:00
224d9cd1c6 feat: Add openapi explorer (#529) 2025-05-04 01:21:54 +02:00
Khaleeq Ahmad
98bc4db193 Fix: Celestial Guardians corrections (#725)
Co-authored-by: Khaleeq Ahmad <1710642+khaleeqahmad@users.noreply.github.com>
2025-05-03 22:42:16 +00:00
yugi-classic
d169a67833 fix: correct data for sets tk-ex-latia, tk-ex-latio, tk-ex-m, tk-ex-p, tk-bw-e, tk-bw-z (#726)
Co-authored-by: Avior <github@avior.me>
2025-05-04 00:37:30 +02:00
d0c43e5ce6 Update build.yml 2025-05-04 00:31:12 +02:00
61f506ee95 fix: build nor running 2025-05-04 00:28:51 +02:00
651be99b41 fix: build not running on PRs 2025-05-04 00:26:48 +02:00
8a8602da96 fix: url not valid 2025-05-04 00:17:36 +02:00
5b1f0528db fix: use the current user instead of the hardcoded user 2025-05-04 00:15:03 +02:00
2e4e3c25ba fix: change status depending on input 2025-05-04 00:08:53 +02:00
c9021ab8fa fix: comment not made 2025-05-04 00:02:43 +02:00
8feda41809 fix: use another token 2025-05-03 23:48:52 +02:00
1eb4c677a7 chore: Add ability to comment on Prs to simplify checking cards (#729) 2025-05-03 23:33:15 +02:00
yugi-classic
b26236e78c feat: Add missing Cards to tk-dp-l (lucario) and tk-dp-m (manaphy) (#721) 2025-05-02 00:43:52 +02:00
aa07e67c80 fix: allow forks to run the build (#723) 2025-05-02 00:39:07 +02:00
961c75c8a0 fix: dex-id url not returning valid cards & filtering not working using dexId (#722) 2025-05-02 00:31:04 +02:00
509288ad19 fix: lillie's clefairy EX having an additionnal attack (#720) 2025-05-02 00:06:20 +02:00
e23bc6c909 feat: update TCG Pocket Promos and fix some issues (#719) 2025-05-01 23:54:36 +02:00
2ca455a957 feat: Add support for ARM servers (#528) 2025-04-30 22:53:22 +02:00
13ad5fb0a2 Revert "feat: added variants to Journey Together cards (#715)" (#717) 2025-04-30 22:46:43 +02:00
Andre Viermann
17a0e241cc feat: added variants to Journey Together cards (#715) 2025-04-30 22:04:22 +02:00
Khaleeq Ahmad
dc51d5e8a8 Fix: A2b Shining Revelry attack amendments (#698)
* Fix: Shining Revelry - Add missing attack damage symbols

* Fix: Shining Revelry - Add missing energy symbols to attack effects

* Fix: Shining Revelry set setails- add foreign language names and update card counts

---------

Co-authored-by: Khaleeq Ahmad <1710642+khaleeqahmad@users.noreply.github.com>
2025-04-30 09:54:55 +02:00
Khaleeq Ahmad
e1de8e8323 feat: Add data TCGP Promo-A 042-059 (March 2025) (#680)
* Add new PTCGP Promo-A cards for March 2025 (42 through 49)

* Add additional cards Promos-A 050 - 059

---------

Co-authored-by: Khaleeq Ahmad <1710642+khaleeqahmad@users.noreply.github.com>
2025-04-30 09:53:54 +02:00
Khaleeq Ahmad
744ad63e3a fix: Triumphant Light corrections (#679)
* Fix Triumphant Light card data and formatting

Fix card data including attack damage modifiers, Palkia and Dalgia Origin forme names and incorrect weakness for Giratina.
Also remove unnecessary HTML formatting from card descriptions

* Remove HTML anchor tags around referenced Pokemon names

---------

Co-authored-by: Khaleeq Ahmad <1710642+khaleeqahmad@users.noreply.github.com>
2025-04-30 09:53:01 +02:00
Simone Anile
6b223c688d Fix evolveFrom for Card 1 of POP Series 3 set (#700)
Updated 
"evolveFrom": "Unown"
to
"evolveFrom": "Wartortle"
2025-04-30 09:51:44 +02:00
Dizo
e749ed01e2 FIX: Prismatic Evolutions set name (Spanish) (#706) 2025-04-30 09:51:31 +02:00
kvacquier
e4eb25b6ea 2025 Rotation (#709) 2025-04-30 09:51:10 +02:00
Octopixell
814f94be6f fix: Add holo variant for sv03-100 (#713)
* fix: Add holo variant for sv03-100

* feat: Add verbose variants for sv03-100

* Update 100.ts

---------

Co-authored-by: Avior <florian.bouillon@delta-wings.net>
2025-04-30 09:50:55 +02:00
yugi-classic
63790a056c feat: Add 1 Missing card in tk-dp-l (#714) 2025-04-30 09:45:36 +02:00
51e017e9cc feat: add Celestial Guardians (#716) 2025-04-30 09:45:00 +02:00
a550cf079c feat: Add Journey Together (#701)
* feat: Add static data for Journey Together

Signed-off-by: Avior <git@avior.me>

* feat: finish naming

Signed-off-by: Avior <git@avior.me>

* should be done

Signed-off-by: Avior <git@avior.me>

* Update index.ts

---------

Signed-off-by: Avior <git@avior.me>
2025-03-29 12:44:17 +01:00
78366685f8 feat: TCG Pocket A2b (#695)
* feat: TCG Pocket A2b

Signed-off-by: Avior <git@avior.me>

* fix:implement new rarities

Signed-off-by: Avior <git@avior.me>

* fix:implement new rarities

Signed-off-by: Avior <git@avior.me>

---------

Signed-off-by: Avior <git@avior.me>
2025-03-27 01:01:27 +01:00
Octopixell
08971af0bf fix: Add holo variants for sv03-013 and sv03-014 (#690)
* fix: Add holo variant for sv03-013

* fix: Add holo variant for sv03-014
2025-03-26 14:56:46 +01:00
Octopixell
7111c33403 fix: Add normal variant for sv01-190 (#689) 2025-03-26 14:55:04 +01:00
Octopixell
a08b8d8cca fix: Add normal variant for sv03-062 (#688) 2025-03-26 14:54:45 +01:00
c3cfb2607a fix: random exit from worker making server not react (#685) 2025-03-12 08:10:49 +01:00
Octopixell
16caf3384e fix: Add holo variant for sv01-134 (#678) 2025-03-11 10:29:48 +01:00
Ziya Fenn
c5ab6d966b Fix Exeggutor ex attack name (#682) 2025-03-11 10:29:18 +01:00
874 changed files with 33335 additions and 1437 deletions

View File

@@ -0,0 +1,21 @@
meta {
name: Get by Dex ID
type: http
seq: 1
}
get {
url: {{BASE_URL}}/v2/en/dex-ids/{{ID}}
body: none
auth: none
}
vars:pre-request {
ID: 162
}
assert {
res.status: eq 200
res.body.cards.length: gte 8
res.body.name: eq {{ID}}
}

View File

@@ -0,0 +1,20 @@
meta {
name: End Star Pattern
type: http
seq: 1
}
get {
url: {{BASE_URL}}/v2/en/cards?name=*chu
body: none
auth: inherit
}
params:query {
name: *chu
}
assert {
res.body.length: gt 3
res.body[1].name: neq Pikachu on the Ball
}

View File

@@ -0,0 +1,19 @@
meta {
name: dexId Search
type: http
seq: 3
}
get {
url: {{BASE_URL}}/v2/ja/cards?dexId=eq:357
body: none
auth: inherit
}
params:query {
dexId: eq:357
}
assert {
res.body.length: eq 3
}

View File

@@ -0,0 +1,20 @@
meta {
name: Start star Pattern
type: http
seq: 2
}
get {
url: {{BASE_URL}}/v2/en/cards?name=fu*
body: none
auth: inherit
}
params:query {
name: fu*
}
assert {
res.body.length: gt 3
res.body[1].name: neq Stufful
}

View File

@@ -19,4 +19,3 @@ dist/
# production
/server/dist
/server/generated

34
.github/scripts/.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# dependencies (bun install)
node_modules
# output
out
dist
*.tgz
# code coverage
coverage
*.lcov
# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# caches
.eslintcache
.cache
*.tsbuildinfo
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

15
.github/scripts/README.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# scripts
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run
```
This project was created using `bun init` in bun v1.2.11. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

106
.github/scripts/bun.lock vendored Normal file
View File

@@ -0,0 +1,106 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "scripts",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.0",
"@tcgdex/sdk": "^2.6.0",
},
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5",
},
},
},
"packages": {
"@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="],
"@actions/exec": ["@actions/exec@1.1.1", "", { "dependencies": { "@actions/io": "^1.0.1" } }, "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w=="],
"@actions/github": ["@actions/github@6.0.0", "", { "dependencies": { "@actions/http-client": "^2.2.0", "@octokit/core": "^5.0.1", "@octokit/plugin-paginate-rest": "^9.0.0", "@octokit/plugin-rest-endpoint-methods": "^10.0.0" } }, "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g=="],
"@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
"@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
"@cachex/core": ["@cachex/core@1.0.1", "", { "dependencies": { "@dzeio/object-util": "^1.8.3" } }, "sha512-sHynwjF9hKIvwg8rTUdvA7MOUMcUC5Mq0dpynPBILRS+IPvsHcE4Cb2uRSs0/I2nxO7NQp9p+xHYistdfJJSwg=="],
"@cachex/memory": ["@cachex/memory@1.0.1", "", { "dependencies": { "@cachex/core": "^1" } }, "sha512-KWUTdCCXhIlAkJaVZMhUh9kD0uq8PxC3Z34Q3lMGZOAV6FXP/cOMW89ALrWX3VkoRrrM4R6MIMO+amZNOvEqgw=="],
"@cachex/web-storage": ["@cachex/web-storage@1.0.1", "", { "dependencies": { "@cachex/core": "^1" } }, "sha512-E8Xa9qDZgNgr+lcj3eixowg7PH2CVZbp3huuoc5xVVTtwYrZi5YqbHBG12yG3r6C6Fts/2Yoq6cbVBSm6c8VRA=="],
"@dzeio/object-util": ["@dzeio/object-util@1.9.1", "", {}, "sha512-cLGsjAc7hzSadS57jcMxSPidYabyZXJOFnasScSrE/V5yflhze6T7L5/98josWYrXMvoKu7N+Ivk6vGkIj72UQ=="],
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
"@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="],
"@octokit/core": ["@octokit/core@5.2.1", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-dKYCMuPO1bmrpuogcjQ8z7ICCH3FP6WmxpwC03yjzGfZhj9fTJg6+bS1+UAplekbN2C+M61UNllGOOoAfGCrdQ=="],
"@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="],
"@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
"@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
"@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@9.2.2", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ=="],
"@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@10.4.1", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg=="],
"@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="],
"@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="],
"@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
"@tcgdex/sdk": ["@tcgdex/sdk@2.6.0", "", { "dependencies": { "@cachex/memory": "^1", "@cachex/web-storage": "^1", "@dzeio/object-util": "^1", "isomorphic-unfetch": "^3" } }, "sha512-q0O7dNzRRLq38XwqUoHFKo78/NCQW5pEIZ+JnlrVOxp9r9R/LTIQGAMNR96Il0hb1uIm4j5o7WBueBCpuDyomQ=="],
"@types/bun": ["@types/bun@1.2.11", "", { "dependencies": { "bun-types": "1.2.11" } }, "sha512-ZLbbI91EmmGwlWTRWuV6J19IUiUC5YQ3TCEuSHI3usIP75kuoA8/0PVF+LTrbEnVc8JIhpElWOxv1ocI1fJBbw=="],
"@types/node": ["@types/node@22.15.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw=="],
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
"bun-types": ["bun-types@1.2.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-dbkp5Lo8HDrXkLrONm6bk+yiiYQSntvFUzQp0v3pzTAsXk6FtgVMjdQ+lzFNVAmQFUkPQZ3WMZqH5tTo+Dp/IA=="],
"deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="],
"isomorphic-unfetch": ["isomorphic-unfetch@3.1.0", "", { "dependencies": { "node-fetch": "^2.6.1", "unfetch": "^4.2.0" } }, "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q=="],
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"unfetch": ["unfetch@4.2.0", "", {}, "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA=="],
"universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
"@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
"@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
"@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
}
}

429
.github/scripts/load-cards.ts vendored Normal file
View File

@@ -0,0 +1,429 @@
import core from "@actions/core";
import github from "@actions/github";
import TCGdex from "@tcgdex/sdk";
// Types
type CardData = {
id: string;
name: string;
image?: string;
rarity?: string;
set: { name: string };
hasImage: boolean;
};
type CardResult = {
file: string;
card?: CardData;
error?: string;
isAsian?: boolean;
usedLanguage?: string;
hasImage?: boolean;
status?: "added" | "removed" | "modified";
};
type CardFetchResult = {
card: any;
usedLanguage: string;
hasImage: boolean;
} | null;
// Constants
const DATA_REGEX = /^data\/([^\/]+)\/([^\/]+)\/([^\/]+)\.ts$/;
const DATA_ASIA_REGEX = /^data-asia\/([^\/]+)\/([^\/]+)\/([^\/]+)\.ts$/;
const INTERNATIONAL_LANGUAGES = ["en", "fr", "es", "es-mx", "it", "pt", "pt-br", "pt-pt", "de", "nl", "pl", "ru"];
const ASIAN_LANGUAGES = ["ja", "ko", "zh-tw", "id", "th", "zh-cn"];
const LANGUAGE_NAMES: Record<string, string> = {
en: "English",
fr: "French",
es: "Spanish",
"es-mx": "Spanish (Mexico)",
it: "Italian",
pt: "Portuguese",
"pt-br": "Portuguese (Brazil)",
"pt-pt": "Portuguese (Portugal)",
de: "German",
nl: "Dutch",
pl: "Polish",
ru: "Russian",
ja: "Japanese",
ko: "Korean",
"zh-tw": "Chinese (Taiwan)",
id: "Indonesian",
th: "Thai",
"zh-cn": "Chinese (China)",
};
// Helper function to sanitize card data
function sanitizeCardData(card: any): CardData | undefined {
if (!card) return undefined;
return {
id: card.id,
name: card.name,
image: card.image,
rarity: card.rarity,
set: card.set ? { name: card.set.name } : { name: "Unknown" },
hasImage: !!card.image,
};
}
// Helper function to try fetching a card with fallback to other languages
async function tryFetchCardWithFallback(
setIdentifier: string,
cardLocalId: string,
primaryLanguage: string,
allLanguages: string[],
isAsianRegion: boolean,
): Promise<CardFetchResult> {
let lastError: Error | unknown = null;
const languagesToTry = [primaryLanguage, ...allLanguages.filter((lang) => lang !== primaryLanguage)];
let foundWithoutImage: { lang: string; card: any } | undefined;
for (const lang of languagesToTry) {
try {
console.log(` Trying language: ${lang}`);
const tcgdex = new TCGdex(lang as any);
let card;
if (!isAsianRegion) {
const set = await tcgdex.set.get(setIdentifier);
card = await tcgdex.card.get(`${set!.id}-${cardLocalId}`);
} else {
card = await tcgdex.card.get(`${setIdentifier}-${cardLocalId}`);
}
if (card && !card.image) {
foundWithoutImage = { lang, card };
continue;
}
if (card && card.image) {
console.log(` Card: ${card.name} (${card.id}) - Found using language: ${lang}`);
return { card, usedLanguage: lang, hasImage: true };
}
} catch (error) {
lastError = error;
console.log(` Failed with language ${lang}: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
if (foundWithoutImage) {
console.log(` Card: ${foundWithoutImage.card.name} (${foundWithoutImage.card.id}) - Found without image`);
return { card: foundWithoutImage.card, usedLanguage: foundWithoutImage.lang, hasImage: false };
}
console.log(
` All languages failed. Last error: ${lastError instanceof Error ? lastError.message : "Unknown error"}`,
);
return null;
}
// Get changed files from GitHub
async function getChangedFiles(
context: typeof github.context,
octokit: ReturnType<typeof github.getOctokit>,
): Promise<{ filename: string; status: string }[]> {
if (context.payload.pull_request) {
const { owner, repo } = context.repo;
const prNumber = context.payload.pull_request.number;
const response = await octokit.rest.pulls.listFiles({
owner,
repo,
pull_number: prNumber,
});
return response.data.map((file) => ({ filename: file.filename, status: file.status }));
} else if (context.payload.commits) {
const files: { filename: string; status: string }[] = [];
for (const commit of context.payload.commits) {
if (commit.added) {
commit.added.forEach((file: string) => files.push({ filename: file, status: "added" }));
}
if (commit.modified) {
commit.modified.forEach((file: string) => files.push({ filename: file, status: "modified" }));
}
if (commit.removed) {
commit.removed.forEach((file: string) => files.push({ filename: file, status: "removed" }));
}
}
return files;
}
return [];
}
// Process a single card file
async function processCardFile(file: { filename: string; status: string }): Promise<CardResult | null> {
console.log(` - ${file.filename} (${file.status})`);
let match = file.filename.match(DATA_REGEX);
const isCardFile = !!(match || file.filename.match(DATA_ASIA_REGEX));
if (!isCardFile) {
return null;
}
// For added files, just return the file info without fetching
if (file.status === "added") {
return {
file: file.filename,
status: "added",
};
}
// For removed files, just return the file info without fetching
if (file.status === "removed") {
return {
file: file.filename,
status: "removed",
};
}
// Only process modified files normally
if (match) {
const [_, , setName, cardLocalId] = match;
const result = await tryFetchCardWithFallback(setName!, cardLocalId!, "en", INTERNATIONAL_LANGUAGES, false);
if (result) {
return {
file: file.filename,
card: sanitizeCardData(result.card),
isAsian: false,
usedLanguage: result.usedLanguage,
hasImage: result.hasImage,
status: "modified",
};
} else {
return {
file: file.filename,
error: "Failed to fetch card information in all available languages",
isAsian: false,
status: "modified",
};
}
}
match = file.filename.match(DATA_ASIA_REGEX);
if (match) {
const [_, , setId, cardLocalId] = match;
const result = await tryFetchCardWithFallback(setId!, cardLocalId!, "ja", ASIAN_LANGUAGES, true);
if (result) {
return {
file: file.filename,
card: sanitizeCardData(result.card),
isAsian: true,
usedLanguage: result.usedLanguage,
hasImage: result.hasImage,
status: "modified",
};
} else {
return {
file: file.filename,
error: "Failed to fetch card information in all available languages",
isAsian: true,
status: "modified",
};
}
}
return null;
}
// Generate comment body for PR
function generateCommentBody(
cardResults: CardResult[],
changedFiles: { filename: string; status: string }[],
repoFullName: string,
contextSha: string,
): string {
const newCards = cardResults.filter((r) => r.status === "added").length;
const deletedCards = cardResults.filter((r) => r.status === "removed").length;
const modifiedCards = cardResults.filter((r) => r.status === "modified" && r.card).length;
const errorCards = cardResults.filter((r) => r.status === "modified" && r.error).length;
const cardsWithoutImages = cardResults.filter((r) => r.card && !r.hasImage).length;
let commentBody = `## 🃏 ${cardResults.length} Card${cardResults.length !== 1 ? "s" : ""} Changed\n\n`;
if (cardResults.length === 0) {
commentBody +=
changedFiles.length > 0
? "No recognized card files were changed in this PR.\n"
: "No files were changed in this PR.\n";
return commentBody;
}
// Add summary
commentBody += `**Details:** `;
const details = [];
if (newCards > 0) {
details.push(`${newCards} new`);
}
if (deletedCards > 0) {
details.push(`${deletedCards} deleted`);
}
if (modifiedCards > 0) {
details.push(`${modifiedCards} modified`);
}
if (errorCards > 0) {
details.push(`${errorCards} with errors`);
}
if (cardsWithoutImages > 0) {
details.push(`${cardsWithoutImages} without images`);
}
commentBody += details.join(", ") + "\n\n";
// Generate detailed card information
for (const item of cardResults) {
const fileUrl = `https://github.com/${repoFullName}/blob/${contextSha}/${item.file}`;
const fileName = item.file.split("/").pop();
if (item.status === "added") {
commentBody += `<details><summary> <strong>New card: ${fileName}</strong></summary>\n\n`;
commentBody += `**File:** [${encodeURI(item.file)}](${encodeURI(fileUrl)}) \n\n`;
commentBody += "</details>\n\n";
} else if (item.status === "removed") {
commentBody += `<details><summary>🗑️ <strong>Deleted card: ${fileName}</strong></summary>\n\n`;
commentBody += `**File:** [${encodeURI(item.file)}](${encodeURI(fileUrl)}) \n\n`;
commentBody += "</details>\n\n";
} else if (item.card) {
const langInfo = item.usedLanguage ? ` (found using ${item.usedLanguage})` : "";
const imageStatus = !item.hasImage ? ` <em>(no images)</em>` : "";
commentBody += `<details><summary><strong>${item.card.name}</strong> (${item.card.id})${langInfo}${imageStatus}</summary>\n\n`;
if (item.card.image) {
const languages = item.isAsian ? ASIAN_LANGUAGES : INTERNATIONAL_LANGUAGES;
commentBody += renderCardImageTable(item.card, languages);
} else {
commentBody += `<p align="center"><em>No images available for this card</em></p>\n\n`;
}
commentBody += `**File:** [${item.file}](${fileUrl}) \n`;
commentBody += `**Set:** ${item.card.set?.name || "Unknown"} \n`;
commentBody += `**Rarity:** ${item.card.rarity || "Unknown"}\n\n`;
commentBody += "</details>\n\n";
} else if (item.error) {
commentBody += `<details><summary>⚠️ <strong>Error processing ${fileName}</strong></summary>\n\n`;
commentBody += `**File:** [${encodeURI(item.file)}](${encodeURI(fileUrl)}) \n\n`;
commentBody += `**Error:** ${item.error}\n\n`;
commentBody += "</details>\n\n";
}
}
return commentBody;
}
// Helper to render the card image table
function renderCardImageTable(card: CardData, languages: string[]): string {
let tableMarkdown = `<div align="center">\n\n`;
tableMarkdown += `| Language | Language | Language |\n`;
tableMarkdown += `|:-------:|:-------:|:-------:|\n`;
for (let i = 0; i < languages.length; i += 3) {
tableMarkdown += `|`;
for (let j = 0; j < 3; j++) {
const langIndex = i + j;
if (langIndex < languages.length) {
const lang = languages[langIndex];
const langName = LANGUAGE_NAMES[lang as keyof typeof LANGUAGE_NAMES] || lang;
const localizedImageUrl = card.image!.replace(/\/[a-z]{2}(-[a-z]{2})?\//, `/${lang}/`);
tableMarkdown += ` <strong>${langName} (${lang})</strong><br><img src="${localizedImageUrl}/high.webp" alt="${card.name} (${langName})" width="200"/> |`;
} else {
tableMarkdown += ` |`;
}
}
tableMarkdown += `\n`;
}
tableMarkdown += `\n</div>\n\n`;
return tableMarkdown;
}
// Post or update PR comment
async function postOrUpdatePRComment(
octokit: ReturnType<typeof github.getOctokit>,
owner: string,
repo: string,
prNumber: number,
commentBody: string,
): Promise<void> {
// Get authenticated user info to identify our bot
const { data: authenticatedUser } = await octokit.rest.users.getAuthenticated();
console.log(`Authenticated as user: ${authenticatedUser.login}`);
const commentsResponse = await octokit.rest.issues.listComments({
owner,
repo,
issue_number: prNumber,
});
// Look for existing comments from our authenticated bot user
const existingComment = commentsResponse.data.find(
(comment) => comment.user?.login === authenticatedUser.login && comment.body?.includes("## 🃏"),
);
if (existingComment) {
await octokit.rest.issues.updateComment({
owner,
repo,
comment_id: existingComment.id,
body: commentBody,
});
console.log(`Updated existing comment #${existingComment.id} on PR #${prNumber} as ${authenticatedUser.login}`);
} else {
await octokit.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: commentBody,
});
console.log(`Posted new comment to PR #${prNumber} as ${authenticatedUser.login}`);
}
}
async function run() {
try {
// Initialize GitHub client
const token = core.getInput("github-token", { required: true });
const octokit = github.getOctokit(token);
const context = github.context;
const { owner, repo } = context.repo;
const repoFullName = `${owner}/${repo}`;
// Get changed files
const changedFiles = await getChangedFiles(context, octokit);
// Process card files
const cardResults: CardResult[] = [];
for (const file of changedFiles) {
const result = await processCardFile(file);
if (result) cardResults.push(result);
}
// Generate comment body
const commentBody = generateCommentBody(cardResults, changedFiles, repoFullName, context.sha);
// Post or update the comment in the PR
if (context.payload.pull_request) {
const prNumber = context.payload.pull_request.number;
await postOrUpdatePRComment(octokit, owner, repo, prNumber, commentBody);
}
// Store the generated comment for the workflow
core.setOutput("pr_comment", commentBody);
core.setOutput("files", changedFiles.map(f => f.filename).join(","));
core.setOutput("cardFiles", JSON.stringify(cardResults));
} catch (error) {
if (error instanceof Error) {
core.setFailed(error.message);
} else {
core.setFailed("An unknown error occurred");
}
}
}
run();

15
.github/scripts/package.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "scripts",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.0",
"@tcgdex/sdk": "^2.6.0"
}
}

28
.github/scripts/tsconfig.json vendored Normal file
View File

@@ -0,0 +1,28 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

View File

@@ -1,63 +1,89 @@
name: Build Docker image
on:
push:
branches:
- '*'
tags:
- v*
pull_request:
branches:
- master
env:
REGISTRY_IMAGE: |
ghcr.io/tcgdex/server
tcgdex/server
jobs:
build:
runs-on: ubuntu-latest
name: Build TCGdex Server
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/tcgdex/server
tcgdex/server
tags: |
type=edge
type=ref,event=pr
type=ref,event=branch,prefix=branch-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=semver,pattern=latest
- name: Checkout
uses: actions/checkout@v4
with:
# fetch full history for `updated` support
fetch-depth: 0
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=edge
type=ref,event=pr
type=ref,event=branch,prefix=branch-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=semver,pattern=latest
- name: Login to Github Packages
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_TOKEN }}
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }}
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Github Packages
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_TOKEN }}
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }}
file: ./Dockerfile
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Pre build server
run: |
bun install --frozen-lockfile
cd server
bun install --frozen-lockfile
bun run compile
rm -rf node_modules
cd ..
rm -rf node_modules
- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
file: ./Dockerfile.github-actions
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
push: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }}
cache-to: type=gha,mode=max

36
.github/workflows/comment-pr.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Card Info Comment
on:
pull_request_target:
types: [opened, synchronize]
paths:
- 'data/**/*.ts'
- 'data-asia/**/*.ts'
jobs:
card-info-comment:
runs-on: ubuntu-latest
continue-on-error: true
defaults:
run:
working-directory: .github/scripts
permissions:
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun i --frozen-lockfile
- name: Run load-cards script
id: load-cards
run: bun load-cards.js
env:
INPUT_GITHUB-TOKEN: ${{ secrets.TCGDEX_BOT }}

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
node_modules/
dist/
.idea

View File

@@ -1,5 +1,4 @@
<!-- omit in toc -->
# Contributing to TCGdex
First off, thanks for taking the time to contribute! ❤️
@@ -7,26 +6,23 @@ First off, thanks for taking the time to contribute! ❤️
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
>
> - Star the project
> - Tweet about it
> - Refer this project in your project's readme
> - Mention the project at local meetups and tell your friends/colleagues
<!-- omit in toc -->
## Table of Contents
- [Code of Conduct](#code-of-conduct)
- [I Have a Question](#i-have-a-question)
- [I Want To Contribute](#i-want-to-contribute)
- [Reporting Issues](#reporting-issues)
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)
- [Improving The Documentation](#improving-the-documentation)
- [Reporting Bugs](#reporting-bugs)
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)
- [Improving The Documentation](#improving-the-documentation)
- [Styleguides](#styleguides)
- [Coding Guidlines](#coding-guidelines)
- [Commit Messages](#commit-messages)
- [Commit Messages](#commit-messages)
- [Join The Project Team](#join-the-project-team)
## Code of Conduct
@@ -37,7 +33,7 @@ By participating, you are expected to uphold this code. Please report unacceptab
## I Have a Question
> If you want to ask a question, we assume that you have read the available Documentation at <https://www.tcgdex.dev>.
> If you want to ask a question, we assume that you have read the available [Documentation](https://tcgdex.dev).
The best way to ask questions is to join our Discord server at <https://discord.gg/NehYTAhsZE>.
@@ -69,38 +65,36 @@ Depending on how large the project is, you may want to outsource the questioning
## I Want To Contribute
> ### Legal Notice <!-- omit in toc -->
>
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project licence.
### Reporting Issues
### Reporting Bugs
<!-- omit in toc -->
#### Before Submitting a Bug Report
#### Before Submitting an Issue Report
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
A good issue report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
- Determine if your issue is not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://www.tcgdex.dev). If you are looking for support, you might want to check [this section](#i-have-a-question)).
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already an issue report existing for your bug or error in the [bug tracker](https://github.com/tcgdex/cards-database/issues).
- Make sure that you are using the latest version.
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://tcgdex.dev). If you are looking for support, you might want to check [this section](#i-have-a-question)).
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https:/github.com/tcgdex/cards-database/issues?q=label%3Abug).
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
- Collect information about the bug:
- Stack trace (Traceback)
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
- Possibly your input and the output
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
- Stack trace (Traceback)
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
- Possibly your input and the output
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
<!-- omit in toc -->
#### How Do I Submit a Good Bug Report?
> You must never report security related issues, vulnerabilities or bugs to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <security@tcgdex.net>.
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <security@tcgdex.net>.
<!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
- Open an [Issue](https://github.com/tcgdex/cards-databaseissues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
- Open an [Issue](https://github.com/tcgdex/cards-database/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
- Explain the behavior you would expect and the actual behavior.
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
- Provide the information you collected in the previous section.
@@ -122,20 +116,19 @@ This section guides you through submitting an enhancement suggestion for TCGdex,
#### Before Submitting an Enhancement
- Make sure that you are using the latest version.
- Read the [documentation](https://www.tcgdex.dev) carefully and find out if the functionality is already covered, maybe by an individual configuration.
- Perform a [search](https://github.com/tcgdex/cards-databaseissues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
- Read the [documentation](https://tcgdex.dev) carefully and find out if the functionality is already covered, maybe by an individual configuration.
- Perform a [search](https://github.com/tcgdex/cards-database/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
<!-- omit in toc -->
#### How Do I Submit a Good Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://github.com/tcgdex/cards-databaseissues).
Enhancement suggestions are tracked as [GitHub issues](https:/github.com/tcgdex/cards-database/issues).
- Use a **clear and descriptive title** for the issue to identify the suggestion.
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI -->
- You may want to **include screenshots or screen recordings** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [LICEcap](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and the built-in [screen recorder in GNOME](https://help.gnome.org/users/gnome-help/stable/screen-shot-record.html.en) or [SimpleScreenRecorder](https://github.com/MaartenBaert/ssr) on Linux. <!-- this should only be included if the project has a GUI -->
- **Explain why this enhancement would be useful** to most TCGdex users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
<!-- You might want to create an issue template for enhancement suggestions that can be used as a guide and that defines the structure of the information to be included. If you do so, reference it here in the description. -->
@@ -150,6 +143,11 @@ _note: Follow the different styleguides listed below when contributing_
- we don't like ❌, so if your pull request has its automated checks ending with the red cross, please double check your changes until it show the awesome 🟢, or ask for help !
- If your pull request is ready for review remove WIP: put it s ready for review and we will handle the rest !
folders :
- `data`: the database for the internationnal cards
- `data-asia`: the database for the asian cards
- `server`: The server behind the API
### Improving The Documentation
The documentation is updated in the Documentation repository at <https://github.com/tcgdex/documentation>
@@ -160,8 +158,8 @@ The documentation is updated in the Documentation repository at <https://github.
Install the plugin `.editorconfig` in your dev environment if it's not already done and thats it !
for those who don't want to install it the basic are these:
- Indent using the `tab` or `\t` character
for those who don't want to install it, the basics are these:
- Indent using the <xkb>tab</xkb> (`\t`) character
- the line feed character is `\n`
- only use `;` when necessary and at the start of the line
- use double quotes `"` when editing files in the `data/` folder and single quote `'` in other files
@@ -195,6 +193,6 @@ In short, please name your Pull Requests/Commits following this format
- use the imperative, present tense: "Change" not "Changed" nor "Changes"
- `<footer>` and `<body>` are both optional
<!-- omit in toc -->
## Attribution
This guide is based on [Contribution Gen]((https://github.com/bttger/contributing-gen)) and was adapted by the TCGdex community !
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!

View File

@@ -10,8 +10,8 @@ RUN apk add git\
USER bun
ADD --chown=bun:bun package.json bun.lockb ./
ADD --chown=bun:bun server/package.json server/bun.lockb ./server/
ADD --chown=bun:bun package.json bun.lock ./
ADD --chown=bun:bun server/package.json server/bun.lock ./server/
# install dependencies
RUN bun install --frozen-lockfile && \

40
Dockerfile.github-actions Normal file
View File

@@ -0,0 +1,40 @@
FROM docker.io/oven/bun:1-alpine AS build
# go to work folder
WORKDIR /usr/src/app
# allow bun user to edit folder
RUN chown -R bun:bun .
USER bun
ADD --chown=bun:bun server/package.json server/bun.lock ./server/
# install prod deps dependencies
RUN cd server && \
bun install --frozen-install --production
# go to another VM
FROM docker.io/oven/bun:1-alpine AS prod
# inform software to be in production
ENV NODE_ENV=production
# run as non root user
USER bun
# go to work folder
WORKDIR /usr/src/app
# copy from build image
COPY --chown=bun:bun ./server/public ./public
COPY --chown=bun:bun ./server/package.json ./package.json
COPY --chown=bun:bun --from=build /usr/src/app/server/node_modules ./node_modules
COPY --chown=bun:bun ./server/src ./src
COPY --chown=bun:bun ./server/generated ./generated
# Expose port
EXPOSE 3000
# run it !
CMD ["bun", "src/index.ts"]

13
bun.lock Normal file
View File

@@ -0,0 +1,13 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"devDependencies": {
"typescript": "^5",
},
},
},
"packages": {
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
}
}

BIN
bun.lockb

Binary file not shown.

View File

@@ -22,7 +22,7 @@ const card: Card = {
],
evolveFrom: {
en: "Unown",
en: "Wartortle",
},
stage: "Stage2",

View File

@@ -0,0 +1,25 @@
import { Set } from '../../interfaces'
import serie from '../Pokémon TCG Pocket'
const set: Set = {
id: "A3",
name: {
de: "Hüter des Firmaments",
en: "Celestial Guardians",
es: "Guardianes Celestiales",
fr: "Gardiens Astraux",
it: "Guardiani Astrali",
pt: "Guardiões Celestiais"
},
serie: serie,
cardCount: {
official: 155
},
releaseDate: "2025-04-30"
}
export default set

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Exeggcute"
},
illustrator: "HYOGONOSUKE",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "Though it may look like it's just a bunch of eggs, it's a proper Pokémon. Exeggcute communicates with others of its kind via telepathy, apparently."
},
stage: "Basic",
attacks: [{
name: {
en: "Rolling Tackle"
},
damage: 30,
cost: ["Grass", "Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Exeggutor"
},
illustrator: "Anesaki Dynamic",
rarity: "Three Diamond",
category: "Pokemon",
hp: 150,
types: ["Grass"],
evolveFrom: {
en: "Exeggcute"
},
description: {
en: "Blazing sunlight has brought out the true form and powers of this Pokémon."
},
stage: "Stage1",
attacks: [{
name: {
en: "Tropical Hammer"
},
damage: 150,
cost: ["Grass", "Colorless", "Colorless"],
effect: {
en: "Flip a coin. If tails, this attack does nothing."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 4
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Surskit"
},
illustrator: "Miki Tanaka",
rarity: "One Diamond",
category: "Pokemon",
hp: 50,
types: ["Grass"],
description: {
en: "They usually live on ponds, but after an evening shower, they may appear on puddles in towns."
},
stage: "Basic",
attacks: [{
name: {
en: "Quick Attack"
},
damage: "10+",
cost: ["Colorless"],
effect: {
en: "Flip a coin. If heads, this attack does 20 more damage."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Masquerain"
},
illustrator: "Kanako Eo",
rarity: "Two Diamond",
category: "Pokemon",
hp: 90,
types: ["Grass"],
evolveFrom: {
en: "Surskit"
},
description: {
en: "It flaps its four wings to hover and fly freely in any direction—to and fro and sideways."
},
stage: "Stage1",
attacks: [{
name: {
en: "Bug Buzz"
},
damage: 40,
cost: ["Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 0
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Maractus"
},
illustrator: "Kagemaru Himeno",
rarity: "One Diamond",
category: "Pokemon",
hp: 90,
types: ["Grass"],
description: {
en: "With noises that could be mistaken for the rattles of maracas, it creates an upbeat rhythm, startling bird Pokémon and making them fly off in a hurry."
},
stage: "Basic",
attacks: [{
name: {
en: "Sting"
},
damage: 40,
cost: ["Grass", "Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Karrablast"
},
illustrator: "OOYAMA",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "Its strange physiology reacts to electrical energy in interesting ways. The presence of a Shelmet will cause this Pokémon to evolve."
},
stage: "Basic",
attacks: [{
name: {
en: "Headbutt"
},
damage: 10,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Phantump"
},
illustrator: "miki kudo",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "After a lost child perished in the forest, their spirit possessed a tree stump, causing the spirit's rebirth as this Pokémon."
},
stage: "Basic",
attacks: [{
name: {
en: "Hook"
},
damage: 20,
cost: ["Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Trevenant"
},
illustrator: "Shin Nagasawa",
rarity: "Two Diamond",
category: "Pokemon",
hp: 130,
types: ["Grass"],
evolveFrom: {
en: "Phantump"
},
description: {
en: "People fear it due to a belief that it devours any who try to cut down trees in its forest, but to the Pokémon it shares its woods with, it's kind."
},
stage: "Stage1",
attacks: [{
name: {
en: "Claw Slash"
},
damage: 80,
cost: ["Grass", "Grass", "Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Rowlet"
},
illustrator: "Megumi Mizutani",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "It sends its feathers, which are as sharp as blades, flying in attack. Its legs are strong, so its kicks are also formidable."
},
stage: "Basic",
attacks: [{
name: {
en: "Leafage"
},
damage: 20,
cost: ["Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,43 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Rowlet"
},
illustrator: "Saya Tsuruta",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "It sends its feathers, which are as sharp as blades, flying in attack. Its legs are strong, so its kicks are also formidable."
},
stage: "Basic",
attacks: [{
name: {
en: "Skill Dive"
},
cost: ["Grass"],
effect: {
en: "This attack does 10 damage to 1 of your opponent's Pokémon."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Dartrix"
},
illustrator: "Mizue",
rarity: "Two Diamond",
category: "Pokemon",
hp: 80,
types: ["Grass"],
evolveFrom: {
en: "Rowlet"
},
description: {
en: "This narcissistic Pokémon is a clean freak. If you don't groom it diligently, it may stop listening to you."
},
stage: "Stage1",
attacks: [{
name: {
en: "Razor Wing"
},
damage: 30,
cost: ["Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,51 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Decidueye ex"
},
illustrator: "PLANETA CG Works",
rarity: "Four Diamond",
category: "Pokemon",
hp: 170,
types: ["Grass"],
evolveFrom: {
en: "Dartrix"
},
stage: "Stage2",
suffix: "EX",
attacks: [{
name: {
en: "Pierce the Pain"
},
cost: ["Colorless", "Colorless"],
effect: {
en: "This attack does 100 damage to 1 of your opponent's Pokémon that have damage on them."
}
}, {
name: {
en: "Razor Leaf"
},
damage: 80,
cost: ["Grass", "Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Grubbin"
},
illustrator: "Yuka Morii",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "Its natural enemies, like Rookidee, may flee rather than risk getting caught in its large mandibles that can snap thick tree branches."
},
stage: "Basic",
attacks: [{
name: {
en: "Gnaw"
},
damage: 10,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Fomantis"
},
illustrator: "Kagemaru Himeno",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "Fomantis hates having its naps interrupted. It fires off beams using energy it gathers by bathing in the sun."
},
stage: "Basic",
attacks: [{
name: {
en: "Leafage"
},
damage: 20,
cost: ["Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,47 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Lurantis"
},
illustrator: "AKIRA EGAWA",
rarity: "Two Diamond",
category: "Pokemon",
hp: 90,
types: ["Grass"],
evolveFrom: {
en: "Fomantis"
},
description: {
en: "By masquerading as a bug Pokémon, it lowers the guard of actual bug Pokémon lured in by a scent of sweet flowers. Its sickles bring them down."
},
stage: "Stage1",
attacks: [{
name: {
en: "Petal Blizzard"
},
cost: ["Grass"],
effect: {
en: "This attack does 20 damage to each of your opponent's Pokémon."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Morelull"
},
illustrator: "You Iribi",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Grass"],
description: {
en: "Pokémon living in the forest eat the delicious caps on Morelull's head. The caps regrow overnight."
},
stage: "Basic",
attacks: [{
name: {
en: "Stampede"
},
damage: 10,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Shiinotic"
},
illustrator: "Suwama Chiaki",
rarity: "Two Diamond",
category: "Pokemon",
hp: 100,
types: ["Grass"],
evolveFrom: {
en: "Morelull"
},
description: {
en: "Its flickering spores lure in prey and put them to sleep. Once this Pokémon has its prey snoozing, it drains their vitality with its fingertips."
},
stage: "Stage1",
attacks: [{
name: {
en: "Flickering Light"
},
damage: 50,
cost: ["Grass", "Colorless"],
effect: {
en: "Flip a coin. If heads, the Defending Pokémon can't attack during your opponent's next turn."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Bounsweet"
},
illustrator: "Akira Komayama",
rarity: "One Diamond",
category: "Pokemon",
hp: 50,
types: ["Grass"],
description: {
en: "Its sweat is sweet, like syrup made from boiled-down fruit. Because of this, Bounsweet was highly valued in the past, when sweeteners were scarce."
},
stage: "Basic",
attacks: [{
name: {
en: "Stampede"
},
damage: 20,
cost: ["Grass"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Steenee"
},
illustrator: "Mizue",
rarity: "Two Diamond",
category: "Pokemon",
hp: 80,
types: ["Grass"],
evolveFrom: {
en: "Bounsweet"
},
description: {
en: "Steenee spreads a sweet scent that makes others feel invigorated. This same scent is popular for antiperspirants."
},
stage: "Stage1",
attacks: [{
name: {
en: "Double Spin"
},
damage: "30x",
cost: ["Grass"],
effect: {
en: "Flip 2 coins. This attack does 30 damage for each heads."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Tsareena"
},
illustrator: "Hasuno",
rarity: "Three Diamond",
category: "Pokemon",
hp: 130,
types: ["Grass"],
evolveFrom: {
en: "Steenee"
},
description: {
en: "This Pokémon is proud and aggressive. However, it is said that a Tsareena will instantly become calm if someone touches the crown on its calyx."
},
stage: "Stage2",
attacks: [{
name: {
en: "Three Kick Combo"
},
damage: "50x",
cost: ["Grass"],
effect: {
en: "Flip 3 coins. This attack does 50 damage for each heads."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,52 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Wimpod"
},
illustrator: "Kagemaru Himeno",
rarity: "One Diamond",
category: "Pokemon",
hp: 70,
types: ["Grass"],
description: {
en: "It's nature's cleaner—it eats anything and everything, including garbage and rotten things. The ground near its nest is always clean."
},
stage: "Basic",
abilities: [{
type: "Ability",
name: {
en: "Wimp Out"
},
effect: {
en: "During your first turn, this Pokémon has no Retreat Cost."
}
}],
attacks: [{
name: {
en: "Gnaw"
},
damage: 30,
cost: ["Grass", "Colorless", "Colorless"]
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Golisopod"
},
illustrator: "Kouki Saitou",
rarity: "Three Diamond",
category: "Pokemon",
hp: 120,
types: ["Grass"],
evolveFrom: {
en: "Wimpod"
},
description: {
en: "It will do anything to win, taking advantage of every opening and finishing opponents off with the small claws on its front legs."
},
stage: "Stage1",
attacks: [{
name: {
en: "First Impression"
},
damage: "60+",
cost: ["Grass", "Grass", "Grass"],
effect: {
en: "If this Pokémon moved from your Bench to the Active Spot this turn, this attack does 60 more damage."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Dhelmise ex"
},
illustrator: "PLANETA Tsuji",
rarity: "Four Diamond",
category: "Pokemon",
hp: 140,
types: ["Grass"],
stage: "Basic",
suffix: "EX",
attacks: [{
name: {
en: "Anchor Shot"
},
damage: 80,
cost: ["Grass", "Grass", "Colorless"],
effect: {
en: "During your opponent's next turn, the Defending Pokémon can't retreat."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Tapu Bulu"
},
illustrator: "Satoshi Shirai",
rarity: "Three Diamond",
category: "Pokemon",
hp: 120,
types: ["Grass"],
description: {
en: "Although it's called a guardian deity, it's violent enough to crush anyone it sees as an enemy."
},
stage: "Basic",
attacks: [{
name: {
en: "Stuck-In Tackle"
},
damage: 100,
cost: ["Grass", "Grass", "Colorless"],
effect: {
en: "Flip a coin. If tails, this Pokémon also does 20 damage to itself."
}
}],
weaknesses: [{
type: "Fire",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Growlithe"
},
illustrator: "Naoyo Kimura",
rarity: "One Diamond",
category: "Pokemon",
hp: 70,
types: ["Fire"],
description: {
en: "It has a brave and trustworthy nature. It fearlessly stands up to bigger and stronger foes."
},
stage: "Basic",
attacks: [{
name: {
en: "Combustion"
},
damage: 30,
cost: ["Fire", "Colorless"]
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Arcanine"
},
illustrator: "match",
rarity: "Two Diamond",
category: "Pokemon",
hp: 130,
types: ["Fire"],
evolveFrom: {
en: "Growlithe"
},
description: {
en: "An ancient picture scroll shows that people were captivated by its movement as it ran through prairies."
},
stage: "Stage1",
attacks: [{
name: {
en: "Fire Mane"
},
damage: 80,
cost: ["Fire", "Fire", "Colorless"]
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Marowak"
},
illustrator: "miki kudo",
rarity: "Two Diamond",
category: "Pokemon",
hp: 110,
types: ["Fire"],
evolveFrom: {
en: "Cubone"
},
description: {
en: "This Pokémon sets the bone it holds on fire and dances through the night as a way to mourn its fallen allies."
},
stage: "Stage1",
attacks: [{
name: {
en: "Burning Bonemerang"
},
damage: "70x",
cost: ["Fire", "Fire", "Colorless"],
effect: {
en: "Flip 2 coins. This attack does 70 damage for each heads. If at least 1 of them is heads, your opponent's Active Pokémon is now Burned."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Fletchinder"
},
illustrator: "Mina Nakai",
rarity: "One Diamond",
category: "Pokemon",
hp: 80,
types: ["Fire"],
evolveFrom: {
en: "Fletchling"
},
description: {
en: "Fletchinder scatters embers in tall grass where bug Pokémon might be hiding and then catches them as they come leaping out."
},
stage: "Stage1",
attacks: [{
name: {
en: "Steady Firebreathing"
},
damage: 30,
cost: ["Fire"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Talonflame"
},
illustrator: "Masakazu Fukuda",
rarity: "Three Diamond",
category: "Pokemon",
hp: 120,
types: ["Fire"],
evolveFrom: {
en: "Fletchinder"
},
description: {
en: "It has top-notch flying capabilities. It flies around easily, even while carrying prey that weighs more than 220 lbs."
},
stage: "Stage2",
attacks: [{
name: {
en: "Fire Wing"
},
damage: 90,
cost: ["Fire", "Fire"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Litten"
},
illustrator: "Akira Komayama",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Fire"],
description: {
en: "If you try too hard to get close to it, it won't open up to you. Even if you do grow close, giving it too much affection is still a no-no."
},
stage: "Basic",
attacks: [{
name: {
en: "Heat Tackle"
},
damage: 30,
cost: ["Fire"],
effect: {
en: "This Pokémon also does 10 damage to itself."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Litten"
},
illustrator: "sui",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Fire"],
description: {
en: "If you try too hard to get close to it, it won't open up to you. Even if you do grow close, giving it too much affection is still a no-no."
},
stage: "Basic",
attacks: [{
name: {
en: "Scratch"
},
damage: 20,
cost: ["Fire"]
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Torracat"
},
illustrator: "tetsuya koizumi",
rarity: "Two Diamond",
category: "Pokemon",
hp: 80,
types: ["Fire"],
evolveFrom: {
en: "Litten"
},
description: {
en: "Torracat will let its Trainer coddle it once they've grown close, but it's a powerful, sharp-clawed Pokémon, so its Trainer gets covered in scratches."
},
stage: "Stage1",
attacks: [{
name: {
en: "Heat Tackle"
},
damage: 40,
cost: ["Fire"],
effect: {
en: "This Pokémon also does 10 damage to itself."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,56 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Incineroar ex"
},
illustrator: "PLANETA CG Works",
rarity: "Four Diamond",
category: "Pokemon",
hp: 180,
types: ["Fire"],
evolveFrom: {
en: "Torracat"
},
stage: "Stage2",
suffix: "EX",
attacks: [{
name: {
en: "Fire Fang"
},
damage: 30,
cost: ["Fire"],
effect: {
en: "Your opponent's Active Pokémon is now Burned."
}
}, {
name: {
en: "Scar-Charged Smash"
},
damage: "80+",
cost: ["Fire", "Fire", "Colorless"],
effect: {
en: "If this Pokémon has damage on it, this attack does 60 more damage."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Oricorio"
},
illustrator: "Jerky",
rarity: "Two Diamond",
category: "Pokemon",
hp: 70,
types: ["Fire"],
description: {
en: "This form of Oricorio has sipped red nectar. It whips up blazing flames as it moves to the steps of its passionate dance."
},
stage: "Basic",
attacks: [{
name: {
en: "Kindle"
},
damage: 40,
cost: ["Fire", "Fire"],
effect: {
en: "Discard a random Energy from both Active Pokémon."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Salandit"
},
illustrator: "Yukiko Baba",
rarity: "One Diamond",
category: "Pokemon",
hp: 50,
types: ["Fire"],
description: {
en: "It taunts its prey and lures them into narrow, rocky areas where it then sprays them with toxic gas to make them dizzy and take them down."
},
stage: "Basic",
attacks: [{
name: {
en: "Gnaw"
},
damage: 20,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Salazzle"
},
illustrator: "Naoki Saito",
rarity: "One Diamond",
category: "Pokemon",
hp: 90,
types: ["Fire"],
evolveFrom: {
en: "Salandit"
},
description: {
en: "Salazzle makes its opponents light-headed with poisonous gas, then captivates them with alluring movements to turn them into loyal servants."
},
stage: "Stage1",
attacks: [{
name: {
en: "Heated Poison"
},
damage: 30,
cost: ["Fire", "Fire"],
effect: {
en: "Your opponent's Active Pokémon is now Poisoned and Burned."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Turtonator"
},
illustrator: "Shin Nagasawa",
rarity: "Three Diamond",
category: "Pokemon",
hp: 120,
types: ["Fire"],
description: {
en: "Explosive substances coat the shell on its back. Enemies that dare attack it will be blown away by an immense detonation."
},
stage: "Basic",
attacks: [{
name: {
en: "Fire Spin"
},
damage: 90,
cost: ["Fire", "Fire", "Colorless"],
effect: {
en: "Discard a Fire Energy from this Pokémon."
}
}],
weaknesses: [{
type: "Water",
value: "+20"
}],
retreat: 4
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Sandshrew"
},
illustrator: "ryoma uratsuka",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Water"],
description: {
en: "Life on mountains covered with deep snow has granted this Pokémon a body of ice that's as hard as steel."
},
stage: "Basic",
attacks: [{
name: {
en: "Scratch"
},
damage: 20,
cost: ["Water"]
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Sandslash"
},
illustrator: "Hasuno",
rarity: "Two Diamond",
category: "Pokemon",
hp: 100,
types: ["Water"],
evolveFrom: {
en: "Alolan Sandshrew"
},
description: {
en: "It uses large, hooked claws to cut a path through deep snow as it runs. On snowy mountains, this Sandslash is faster than any other Pokémon."
},
stage: "Stage1",
attacks: [{
name: {
en: "Spike Armor"
},
damage: 20,
cost: ["Water"],
effect: {
en: "During your opponent's next turn, if this Pokémon is damaged by an attack, do 40 damage to the Attacking Pokémon."
}
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,43 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Vulpix"
},
illustrator: "You Iribi",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Water"],
description: {
en: "After long years in the ever-snowcapped mountains of Alola, this Vulpix has gained power over ice."
},
stage: "Basic",
attacks: [{
name: {
en: "Call Forth Cold"
},
cost: ["Water"],
effect: {
en: "Take a Water Energy from your Energy Zone and attach it to this Pokémon."
}
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Ninetales"
},
illustrator: "Eri Yamaki",
rarity: "Three Diamond",
category: "Pokemon",
hp: 110,
types: ["Water"],
evolveFrom: {
en: "Alolan Vulpix"
},
description: {
en: "A deity resides in the snowy mountains where this Pokémon lives. In ancient times, it was worshiped as that deity's incarnation."
},
stage: "Stage1",
attacks: [{
name: {
en: "Blizzard"
},
damage: 60,
cost: ["Water", "Water", "Water"],
effect: {
en: "This attack also does 20 damage to each of your opponent's Benched Pokémon."
}
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Shellder"
},
illustrator: "Midori Harada",
rarity: "One Diamond",
category: "Pokemon",
hp: 70,
types: ["Water"],
description: {
en: "It is encased in a shell that is harder than diamond. Inside, however, it is surprisingly tender."
},
stage: "Basic",
attacks: [{
name: {
en: "Tackle"
},
damage: 10,
cost: ["Water"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Cloyster"
},
illustrator: "Masakazu Fukuda",
rarity: "Two Diamond",
category: "Pokemon",
hp: 110,
types: ["Water"],
evolveFrom: {
en: "Shellder"
},
description: {
en: "Cloyster that live in seas with harsh tidal currents grow large, sharp spikes on their shells."
},
stage: "Stage1",
attacks: [{
name: {
en: "Guard Press"
},
damage: 50,
cost: ["Water", "Water"],
effect: {
en: "During your opponent's next turn, this Pokémon takes 20 damage from attacks."
}
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Lapras"
},
illustrator: "Hitoshi Ariga",
rarity: "Two Diamond",
category: "Pokemon",
hp: 110,
types: ["Water"],
description: {
en: "A smart and kindhearted Pokémon, it glides across the surface of the sea while its beautiful song echoes around it."
},
stage: "Basic",
attacks: [{
name: {
en: "Surf"
},
damage: 70,
cost: ["Water", "Water", "Colorless"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,43 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Popplio"
},
illustrator: "Kanami Ogata",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Water"],
description: {
en: "The balloons it inflates with its nose grow larger and larger as it practices day by day."
},
stage: "Basic",
attacks: [{
name: {
en: "Sing"
},
cost: ["Colorless"],
effect: {
en: "Your opponent's Active Pokémon is now Asleep."
}
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Popplio"
},
illustrator: "Kouki Saitou",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Water"],
description: {
en: "The balloons it inflates with its nose grow larger and larger as it practices day by day."
},
stage: "Basic",
attacks: [{
name: {
en: "Water Gun"
},
damage: 20,
cost: ["Water"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Brionne"
},
illustrator: "Saya Tsuruta",
rarity: "Two Diamond",
category: "Pokemon",
hp: 80,
types: ["Water"],
evolveFrom: {
en: "Popplio"
},
description: {
en: "It gets excited when it sees a dance it doesn't know. This hard worker practices diligently until it can learn that dance."
},
stage: "Stage1",
attacks: [{
name: {
en: "Wave Splash"
},
damage: 30,
cost: ["Water"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,56 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Primarina"
},
illustrator: "Kagemaru Himeno",
rarity: "Three Diamond",
category: "Pokemon",
hp: 140,
types: ["Water"],
evolveFrom: {
en: "Brionne"
},
description: {
en: "To Primarina, every battle is a stage. It takes down its prey with beautiful singing and dancing."
},
stage: "Stage2",
abilities: [{
type: "Ability",
name: {
en: "Melodious Healing"
},
effect: {
en: "Once during your turn, you may heal 30 damage from each of your Water Pokémon."
}
}],
attacks: [{
name: {
en: "Surf"
},
damage: 60,
cost: ["Water", "Colorless"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,45 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Crabominable ex"
},
illustrator: "PLANETA CG Works",
rarity: "Four Diamond",
category: "Pokemon",
hp: 160,
types: ["Water"],
evolveFrom: {
en: "Crabrawler"
},
stage: "Stage1",
suffix: "EX",
attacks: [{
name: {
en: "Insatiable Striking"
},
damage: 40,
cost: ["Water"],
effect: {
en: "During your next turn, this Pokémon's Insatiable Striking attack does +40 damage."
}
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,43 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Wishiwashi"
},
illustrator: "Kouki Saitou",
rarity: "One Diamond",
category: "Pokemon",
hp: 30,
types: ["Water"],
description: {
en: "Individually, they're incredibly weak. It's by gathering up into schools that they're able to confront opponents."
},
stage: "Basic",
attacks: [{
name: {
en: "Call for Family"
},
cost: ["Water"],
effect: {
en: "Put 1 random Wishiwashi or Wishiwashi ex from your deck onto your Bench."
}
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Wishiwashi ex"
},
illustrator: "PLANETA CG Works",
rarity: "Four Diamond",
category: "Pokemon",
hp: 170,
types: ["Water"],
stage: "Basic",
suffix: "EX",
attacks: [{
name: {
en: "School Storm"
},
damage: "30+",
cost: ["Water", "Water", "Water"],
effect: {
en: "This attack does 40 more damage for each of your Benched Wishiwashi and Wishiwashi ex."
}
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Dewpider"
},
illustrator: "Atsuko Nishida",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Water"],
description: {
en: "It forms a water bubble at the rear of its body and then covers its head with it. Meeting another Dewpider means comparing water-bubble sizes."
},
stage: "Basic",
attacks: [{
name: {
en: "Hook"
},
damage: 30,
cost: ["Water", "Colorless"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Araquanid"
},
illustrator: "kodama",
rarity: "Two Diamond",
category: "Pokemon",
hp: 110,
types: ["Water"],
evolveFrom: {
en: "Dewpider"
},
description: {
en: "It launches water bubbles with its legs, drowning prey within the bubbles. This Pokémon can then take its time to savor its meal."
},
stage: "Stage1",
attacks: [{
name: {
en: "Dangerous Claws"
},
damage: "60+",
cost: ["Water", "Water", "Colorless"],
effect: {
en: "If your opponent's Active Pokémon is a Basic Pokémon, this attack does 60 more damage."
}
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,52 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Pyukumuku"
},
illustrator: "You Iribi",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Water"],
description: {
en: "It lives in warm, shallow waters. If it encounters a foe, it will spit out its internal organs as a means to punch them."
},
stage: "Basic",
abilities: [{
type: "Ability",
name: {
en: "Innards Out"
},
effect: {
en: "If this Pokémon is in the Active Spot and is Knocked Out by damage from an attack from your opponent's Pokémon, do 50 damage to the Attacking Pokémon."
}
}],
attacks: [{
name: {
en: "Sprinkle Water"
},
damage: 20,
cost: ["Water"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Bruxish"
},
illustrator: "Masakazu Fukuda",
rarity: "One Diamond",
category: "Pokemon",
hp: 80,
types: ["Water"],
description: {
en: "It grinds its teeth with great force to stimulate its brain. It fires the psychic energy created by this process from the protuberance on its head."
},
stage: "Basic",
attacks: [{
name: {
en: "Wave Splash"
},
damage: 50,
cost: ["Water", "Colorless"]
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Tapu Fini"
},
illustrator: "chibi",
rarity: "Three Diamond",
category: "Pokemon",
hp: 100,
types: ["Water"],
description: {
en: "This guardian deity of Poni Island manipulates water. Because it lives deep within a thick fog, it came to be both feared and revered."
},
stage: "Basic",
attacks: [{
name: {
en: "Spiral Drain"
},
damage: 60,
cost: ["Water", "Water", "Colorless"],
effect: {
en: "Heal 20 damage from this Pokémon."
}
}],
weaknesses: [{
type: "Lightning",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Pikachu"
},
illustrator: "Naoyo Kimura",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Lightning"],
description: {
en: "When it is angered, it immediately discharges the energy stored in the pouches in its cheeks."
},
stage: "Basic",
attacks: [{
name: {
en: "Tail Smack"
},
damage: 30,
cost: ["Colorless", "Colorless"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,45 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Raichu ex"
},
illustrator: "PLANETA CG Works",
rarity: "Four Diamond",
category: "Pokemon",
hp: 140,
types: ["Lightning"],
evolveFrom: {
en: "Pikachu"
},
stage: "Stage1",
suffix: "EX",
attacks: [{
name: {
en: "Psychic"
},
damage: "60+",
cost: ["Colorless", "Colorless", "Colorless"],
effect: {
en: "This attack does 30 more damage for each Energy attached to your opponent's Active Pokémon."
}
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Geodude"
},
illustrator: "Hitoshi Ariga",
rarity: "One Diamond",
category: "Pokemon",
hp: 70,
types: ["Lightning"],
description: {
en: "If you mistake it for a rock and step on it, it will headbutt you in anger. In addition to the pain, it will also zap you with a shock."
},
stage: "Basic",
attacks: [{
name: {
en: "Knuckle Punch"
},
damage: 40,
cost: ["Lightning", "Colorless"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Graveler"
},
illustrator: "match",
rarity: "Two Diamond",
category: "Pokemon",
hp: 110,
types: ["Lightning"],
evolveFrom: {
en: "Alolan Geodude"
},
description: {
en: "When two Graveler fight each other, it fills the surroundings with flashes of light and sound. People call it the \"fireworks of the earth.\""
},
stage: "Stage1",
attacks: [{
name: {
en: "Heavy Impact"
},
damage: 60,
cost: ["Lightning", "Colorless", "Colorless"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 3
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Alolan Golem"
},
illustrator: "kawayoo",
rarity: "Three Diamond",
category: "Pokemon",
hp: 160,
types: ["Lightning"],
evolveFrom: {
en: "Alolan Graveler"
},
description: {
en: "It's grumpy and stubborn. If you upset it, it discharges electricity from the surface of its body and growls with a voice like thunder."
},
stage: "Stage2",
attacks: [{
name: {
en: "Super Zap Cannon"
},
damage: 150,
cost: ["Lightning", "Lightning", "Colorless", "Colorless"],
effect: {
en: "Discard 2 Lightning Energy from this Pokémon."
}
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 4
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Helioptile"
},
illustrator: "0313",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Lightning"],
description: {
en: "When spread, the frills on its head act like solar panels, generating the power behind this Pokémon's electric moves."
},
stage: "Basic",
attacks: [{
name: {
en: "Smash Kick"
},
damage: 10,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Heliolisk"
},
illustrator: "Kagemaru Himeno",
rarity: "One Diamond",
category: "Pokemon",
hp: 90,
types: ["Lightning"],
evolveFrom: {
en: "Helioptile"
},
description: {
en: "One Heliolisk basking in the sun with its frill outspread is all it would take to produce enough electricity to power a city."
},
stage: "Stage1",
attacks: [{
name: {
en: "Rear Kick"
},
damage: 40,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Charjabug"
},
illustrator: "Naoki Saito",
rarity: "Two Diamond",
category: "Pokemon",
hp: 90,
types: ["Lightning"],
evolveFrom: {
en: "Grubbin"
},
description: {
en: "While its durable shell protects it from attacks, Charjabug strikes at enemies with jolts of electricity discharged from the tips of its jaws."
},
stage: "Stage1",
attacks: [{
name: {
en: "Vise Grip"
},
damage: 30,
cost: ["Lightning"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Vikavolt"
},
illustrator: "Hitoshi Ariga",
rarity: "Three Diamond",
category: "Pokemon",
hp: 140,
types: ["Lightning"],
evolveFrom: {
en: "Charjabug"
},
description: {
en: "It builds up electricity in its abdomen, focuses it through its jaws, and then fires the electricity off in concentrated beams."
},
stage: "Stage2",
attacks: [{
name: {
en: "Disconnect"
},
damage: 70,
cost: ["Lightning", "Lightning"],
effect: {
en: "During your opponent's next turn, they can't play any Item cards from their hand."
}
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,52 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Oricorio"
},
illustrator: "Jerky",
rarity: "Three Diamond",
category: "Pokemon",
hp: 70,
types: ["Lightning"],
description: {
en: "This form of Oricorio has sipped yellow nectar. It uses nimble steps to approach opponents, then knocks them out with electric punches."
},
stage: "Basic",
abilities: [{
type: "Ability",
name: {
en: "Safeguard"
},
effect: {
en: "Prevent all damage done to this Pokémon by attacks from your opponent's Pokémon ex."
}
}],
attacks: [{
name: {
en: "Zzzap"
},
damage: 50,
cost: ["Lightning", "Colorless"]
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Togedemaru"
},
illustrator: "Misa Tsutsui",
rarity: "One Diamond",
category: "Pokemon",
hp: 70,
types: ["Lightning"],
description: {
en: "With the long hairs on its back, this Pokémon takes in electricity from other electric Pokémon. It stores what it absorbs in an electric sac."
},
stage: "Basic",
attacks: [{
name: {
en: "Electrosmash"
},
damage: "20+",
cost: ["Lightning"],
effect: {
en: "Flip a coin. If heads, this attack does 30 more damage."
}
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Tapu Koko"
},
illustrator: "kirisAki",
rarity: "Three Diamond",
category: "Pokemon",
hp: 100,
types: ["Lightning"],
description: {
en: "Although it's called a guardian deity, if a person or Pokémon puts it in a bad mood, it will become a malevolent deity and attack."
},
stage: "Basic",
attacks: [{
name: {
en: "Volt Switch"
},
damage: 70,
cost: ["Lightning", "Lightning", "Lightning"],
effect: {
en: "Switch this Pokémon with 1 of your Benched Lightning Pokémon."
}
}],
weaknesses: [{
type: "Fighting",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Mr. Mime"
},
illustrator: "Yukihiro Tada",
rarity: "Two Diamond",
category: "Pokemon",
hp: 80,
types: ["Psychic"],
description: {
en: "The broadness of its hands may be no coincidence—many scientists believe its palms became enlarged specifically for pantomiming."
},
stage: "Basic",
attacks: [{
name: {
en: "Barrier Shove"
},
damage: 30,
cost: ["Psychic", "Colorless"],
effect: {
en: "Flip a coin. If heads, during your opponent's next turn, prevent all damage from—and effects of—attacks done to this Pokémon."
}
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Sableye"
},
illustrator: "Aya Kusube",
rarity: "Two Diamond",
category: "Pokemon",
hp: 80,
types: ["Psychic"],
description: {
en: "It dwells in the darkness of caves. It uses its sharp claws to dig up gems to nourish itself."
},
stage: "Basic",
attacks: [{
name: {
en: "Corner"
},
damage: 40,
cost: ["Psychic", "Colorless"],
effect: {
en: "During your opponent's next turn, the Defending Pokémon can't retreat."
}
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,43 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Spoink"
},
illustrator: "Sekio",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Psychic"],
description: {
en: "Spoink will die if it stops bouncing. The pearl on its head amplifies its psychic powers."
},
stage: "Basic",
attacks: [{
name: {
en: "Psycharge"
},
cost: ["Psychic"],
effect: {
en: "Take a Psychic Energy from your Energy Zone and attach it to this Pokémon."
}
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Grumpig"
},
illustrator: "Yukiko Baba",
rarity: "Two Diamond",
category: "Pokemon",
hp: 110,
types: ["Psychic"],
evolveFrom: {
en: "Spoink"
},
description: {
en: "It can perform odd dance steps to influence foes. Its style of dancing became hugely popular overseas."
},
stage: "Stage1",
attacks: [{
name: {
en: "Zen Headbutt"
},
damage: 70,
cost: ["Psychic", "Colorless", "Colorless"]
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Lunatone"
},
illustrator: "Hisao Nakamura",
rarity: "One Diamond",
category: "Pokemon",
hp: 90,
types: ["Psychic"],
description: {
en: "The phase of the moon apparently has some effect on its power. It's active on the night of a full moon."
},
stage: "Basic",
attacks: [{
name: {
en: "Moon Press"
},
damage: 50,
cost: ["Psychic", "Colorless"]
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 2
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Shuppet"
},
illustrator: "Kyoko Umemoto",
rarity: "One Diamond",
category: "Pokemon",
hp: 60,
types: ["Psychic"],
description: {
en: "It loves to feed on feelings like envy and malice. Its upright horn catches the emotions of people."
},
stage: "Basic",
attacks: [{
name: {
en: "Will-O-Wisp"
},
damage: 20,
cost: ["Psychic"]
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,48 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Banette"
},
illustrator: "Aya Kusube",
rarity: "One Diamond",
category: "Pokemon",
hp: 90,
types: ["Psychic"],
evolveFrom: {
en: "Shuppet"
},
description: {
en: "This Pokémon developed from an abandoned doll that amassed a grudge. It is seen in dark alleys."
},
stage: "Stage1",
attacks: [{
name: {
en: "Night Bind"
},
damage: 30,
cost: ["Psychic"],
effect: {
en: "During your opponent's next turn, they can't take any Energy from their Energy Zone to attach to their Active Pokémon."
}
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Oricorio"
},
illustrator: "Jerky",
rarity: "Two Diamond",
category: "Pokemon",
hp: 70,
types: ["Psychic"],
description: {
en: "This form of Oricorio has sipped pink nectar. It elevates its mind with the gentle steps of its dance, then unleashes its psychic energy."
},
stage: "Basic",
attacks: [{
name: {
en: "Dazzle Dance"
},
damage: 40,
cost: ["Psychic", "Psychic"],
effect: {
en: "Your opponent's Active Pokémon is now Confused."
}
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Oricorio"
},
illustrator: "Jerky",
rarity: "Two Diamond",
category: "Pokemon",
hp: 70,
types: ["Psychic"],
description: {
en: "This form of Oricorio has sipped purple nectar. It uses ethereal dance steps to call forth the spirits of the dead."
},
stage: "Basic",
attacks: [{
name: {
en: "Spiteful Dance"
},
damage: "20+",
cost: ["Psychic"],
effect: {
en: "If any of your Pokémon were Knocked Out by damage from an attack during your opponent's last turn, this attack does 60 more damage."
}
}],
weaknesses: [{
type: "Darkness",
value: "+20"
}],
retreat: 1
}
export default card

View File

@@ -0,0 +1,40 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Cutiefly"
},
illustrator: "Hitoshi Ariga",
rarity: "One Diamond",
category: "Pokemon",
hp: 30,
types: ["Psychic"],
description: {
en: "Nectar and pollen are its favorite fare. In fields of flowers, it gets into skirmishes with Butterfree over food."
},
stage: "Basic",
attacks: [{
name: {
en: "Flap"
},
damage: 10,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 0
}
export default card

View File

@@ -0,0 +1,44 @@
import { Card } from "../../../interfaces"
import Set from "../Celestial Guardians"
const card: Card = {
set: Set,
name: {
en: "Ribombee"
},
illustrator: "Megumi Mizutani",
rarity: "One Diamond",
category: "Pokemon",
hp: 80,
types: ["Psychic"],
evolveFrom: {
en: "Cutiefly"
},
description: {
en: "It makes pollen puffs from pollen and nectar. The puffs' effects depend on the type of ingredients and how much of each one is used."
},
stage: "Stage1",
attacks: [{
name: {
en: "Fairy Wind"
},
damage: 40,
cost: ["Colorless"]
}],
weaknesses: [{
type: "Metal",
value: "+20"
}],
retreat: 0
}
export default card

Some files were not shown because too many files have changed in this diff Show More