diff --git a/output/heron/001.svg b/output/heron/001.svg
index 5983f52..3bfa7db 100644
--- a/output/heron/001.svg
+++ b/output/heron/001.svg
@@ -2,9 +2,6 @@
\ No newline at end of file
diff --git a/output/heron/002.svg b/output/heron/002.svg
new file mode 100644
index 0000000..6f04c74
--- /dev/null
+++ b/output/heron/002.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/output/heron/003.svg b/output/heron/003.svg
new file mode 100644
index 0000000..2968567
--- /dev/null
+++ b/output/heron/003.svg
@@ -0,0 +1,60 @@
+
+
\ No newline at end of file
diff --git a/output/heron/004.svg b/output/heron/004.svg
new file mode 100644
index 0000000..b183356
--- /dev/null
+++ b/output/heron/004.svg
@@ -0,0 +1,63 @@
+
+
\ No newline at end of file
diff --git a/output/heron/005.svg b/output/heron/005.svg
new file mode 100644
index 0000000..2dbbddd
--- /dev/null
+++ b/output/heron/005.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/006.svg b/output/heron/006.svg
new file mode 100644
index 0000000..903ab8f
--- /dev/null
+++ b/output/heron/006.svg
@@ -0,0 +1,71 @@
+
+
\ No newline at end of file
diff --git a/output/heron/007.svg b/output/heron/007.svg
new file mode 100644
index 0000000..19644d4
--- /dev/null
+++ b/output/heron/007.svg
@@ -0,0 +1,69 @@
+
+
\ No newline at end of file
diff --git a/output/heron/008.svg b/output/heron/008.svg
new file mode 100644
index 0000000..a521ec1
--- /dev/null
+++ b/output/heron/008.svg
@@ -0,0 +1,65 @@
+
+
\ No newline at end of file
diff --git a/output/heron/009.svg b/output/heron/009.svg
new file mode 100644
index 0000000..c04fc75
--- /dev/null
+++ b/output/heron/009.svg
@@ -0,0 +1,65 @@
+
+
\ No newline at end of file
diff --git a/output/heron/010.svg b/output/heron/010.svg
index cb840fd..c12cad4 100644
--- a/output/heron/010.svg
+++ b/output/heron/010.svg
@@ -2,9 +2,6 @@
\ No newline at end of file
diff --git a/output/heron/011.svg b/output/heron/011.svg
new file mode 100644
index 0000000..d34d179
--- /dev/null
+++ b/output/heron/011.svg
@@ -0,0 +1,71 @@
+
+
\ No newline at end of file
diff --git a/output/heron/012.svg b/output/heron/012.svg
new file mode 100644
index 0000000..12c31e8
--- /dev/null
+++ b/output/heron/012.svg
@@ -0,0 +1,63 @@
+
+
\ No newline at end of file
diff --git a/output/heron/013.svg b/output/heron/013.svg
index 683ec8a..2547979 100644
--- a/output/heron/013.svg
+++ b/output/heron/013.svg
@@ -2,9 +2,6 @@
\ No newline at end of file
diff --git a/output/heron/014.svg b/output/heron/014.svg
new file mode 100644
index 0000000..a944c46
--- /dev/null
+++ b/output/heron/014.svg
@@ -0,0 +1,67 @@
+
+
\ No newline at end of file
diff --git a/output/heron/015.svg b/output/heron/015.svg
new file mode 100644
index 0000000..07a891d
--- /dev/null
+++ b/output/heron/015.svg
@@ -0,0 +1,60 @@
+
+
\ No newline at end of file
diff --git a/output/heron/016.svg b/output/heron/016.svg
new file mode 100644
index 0000000..f936b95
--- /dev/null
+++ b/output/heron/016.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/017.svg b/output/heron/017.svg
new file mode 100644
index 0000000..b6d5aea
--- /dev/null
+++ b/output/heron/017.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/018.svg b/output/heron/018.svg
new file mode 100644
index 0000000..a62db97
--- /dev/null
+++ b/output/heron/018.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/019.svg b/output/heron/019.svg
new file mode 100644
index 0000000..458643c
--- /dev/null
+++ b/output/heron/019.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/020.svg b/output/heron/020.svg
new file mode 100644
index 0000000..551a70c
--- /dev/null
+++ b/output/heron/020.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/021.svg b/output/heron/021.svg
new file mode 100644
index 0000000..4bb547c
--- /dev/null
+++ b/output/heron/021.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/022.svg b/output/heron/022.svg
new file mode 100644
index 0000000..e75d08b
--- /dev/null
+++ b/output/heron/022.svg
@@ -0,0 +1,71 @@
+
+
\ No newline at end of file
diff --git a/output/heron/023.svg b/output/heron/023.svg
new file mode 100644
index 0000000..e0e33ed
--- /dev/null
+++ b/output/heron/023.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/output/heron/024.svg b/output/heron/024.svg
new file mode 100644
index 0000000..3623839
--- /dev/null
+++ b/output/heron/024.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/025.svg b/output/heron/025.svg
new file mode 100644
index 0000000..24f6579
--- /dev/null
+++ b/output/heron/025.svg
@@ -0,0 +1,58 @@
+
+
\ No newline at end of file
diff --git a/output/heron/026.svg b/output/heron/026.svg
new file mode 100644
index 0000000..c625c20
--- /dev/null
+++ b/output/heron/026.svg
@@ -0,0 +1,64 @@
+
+
\ No newline at end of file
diff --git a/output/heron/027.svg b/output/heron/027.svg
new file mode 100644
index 0000000..94cc2bb
--- /dev/null
+++ b/output/heron/027.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/028.svg b/output/heron/028.svg
new file mode 100644
index 0000000..ee0259e
--- /dev/null
+++ b/output/heron/028.svg
@@ -0,0 +1,63 @@
+
+
\ No newline at end of file
diff --git a/output/heron/029.svg b/output/heron/029.svg
new file mode 100644
index 0000000..17c2892
--- /dev/null
+++ b/output/heron/029.svg
@@ -0,0 +1,74 @@
+
+
\ No newline at end of file
diff --git a/output/heron/030.svg b/output/heron/030.svg
new file mode 100644
index 0000000..10fabd4
--- /dev/null
+++ b/output/heron/030.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/031.svg b/output/heron/031.svg
new file mode 100644
index 0000000..c857115
--- /dev/null
+++ b/output/heron/031.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/032.svg b/output/heron/032.svg
new file mode 100644
index 0000000..6bd6028
--- /dev/null
+++ b/output/heron/032.svg
@@ -0,0 +1,60 @@
+
+
\ No newline at end of file
diff --git a/output/heron/033.svg b/output/heron/033.svg
new file mode 100644
index 0000000..52f0472
--- /dev/null
+++ b/output/heron/033.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/034.svg b/output/heron/034.svg
new file mode 100644
index 0000000..5c2e5ab
--- /dev/null
+++ b/output/heron/034.svg
@@ -0,0 +1,64 @@
+
+
\ No newline at end of file
diff --git a/output/heron/035.svg b/output/heron/035.svg
new file mode 100644
index 0000000..803571a
--- /dev/null
+++ b/output/heron/035.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/036.svg b/output/heron/036.svg
new file mode 100644
index 0000000..2aef616
--- /dev/null
+++ b/output/heron/036.svg
@@ -0,0 +1,58 @@
+
+
\ No newline at end of file
diff --git a/output/heron/037.svg b/output/heron/037.svg
new file mode 100644
index 0000000..460c1bf
--- /dev/null
+++ b/output/heron/037.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/038.svg b/output/heron/038.svg
new file mode 100644
index 0000000..4a1bcc0
--- /dev/null
+++ b/output/heron/038.svg
@@ -0,0 +1,60 @@
+
+
\ No newline at end of file
diff --git a/output/heron/039.svg b/output/heron/039.svg
new file mode 100644
index 0000000..83d277c
--- /dev/null
+++ b/output/heron/039.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/040.svg b/output/heron/040.svg
new file mode 100644
index 0000000..5596788
--- /dev/null
+++ b/output/heron/040.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/output/heron/041.svg b/output/heron/041.svg
new file mode 100644
index 0000000..f730ea0
--- /dev/null
+++ b/output/heron/041.svg
@@ -0,0 +1,59 @@
+
+
\ No newline at end of file
diff --git a/output/heron/042.svg b/output/heron/042.svg
new file mode 100644
index 0000000..9166746
--- /dev/null
+++ b/output/heron/042.svg
@@ -0,0 +1,64 @@
+
+
\ No newline at end of file
diff --git a/output/heron/043.svg b/output/heron/043.svg
new file mode 100644
index 0000000..a9118db
--- /dev/null
+++ b/output/heron/043.svg
@@ -0,0 +1,64 @@
+
+
\ No newline at end of file
diff --git a/output/heron/044.svg b/output/heron/044.svg
new file mode 100644
index 0000000..5ac70b6
--- /dev/null
+++ b/output/heron/044.svg
@@ -0,0 +1,71 @@
+
+
\ No newline at end of file
diff --git a/output/heron/045.svg b/output/heron/045.svg
new file mode 100644
index 0000000..f1956a1
--- /dev/null
+++ b/output/heron/045.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/046.svg b/output/heron/046.svg
new file mode 100644
index 0000000..c731489
--- /dev/null
+++ b/output/heron/046.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/047.svg b/output/heron/047.svg
new file mode 100644
index 0000000..c735476
--- /dev/null
+++ b/output/heron/047.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/output/heron/048.svg b/output/heron/048.svg
new file mode 100644
index 0000000..ff6baa6
--- /dev/null
+++ b/output/heron/048.svg
@@ -0,0 +1,62 @@
+
+
\ No newline at end of file
diff --git a/output/heron/049.svg b/output/heron/049.svg
new file mode 100644
index 0000000..587d44b
--- /dev/null
+++ b/output/heron/049.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/output/heron/050.svg b/output/heron/050.svg
new file mode 100644
index 0000000..71c0c0c
--- /dev/null
+++ b/output/heron/050.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/051.svg b/output/heron/051.svg
new file mode 100644
index 0000000..5c25217
--- /dev/null
+++ b/output/heron/051.svg
@@ -0,0 +1,60 @@
+
+
\ No newline at end of file
diff --git a/output/heron/052.svg b/output/heron/052.svg
new file mode 100644
index 0000000..1a62133
--- /dev/null
+++ b/output/heron/052.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/053.svg b/output/heron/053.svg
new file mode 100644
index 0000000..e89be39
--- /dev/null
+++ b/output/heron/053.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/054.svg b/output/heron/054.svg
new file mode 100644
index 0000000..af777f7
--- /dev/null
+++ b/output/heron/054.svg
@@ -0,0 +1,63 @@
+
+
\ No newline at end of file
diff --git a/output/heron/055.svg b/output/heron/055.svg
new file mode 100644
index 0000000..eef706f
--- /dev/null
+++ b/output/heron/055.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/056.svg b/output/heron/056.svg
new file mode 100644
index 0000000..f443189
--- /dev/null
+++ b/output/heron/056.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/057.svg b/output/heron/057.svg
new file mode 100644
index 0000000..83774a4
--- /dev/null
+++ b/output/heron/057.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/058.svg b/output/heron/058.svg
new file mode 100644
index 0000000..e937de6
--- /dev/null
+++ b/output/heron/058.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/059.svg b/output/heron/059.svg
new file mode 100644
index 0000000..e57222d
--- /dev/null
+++ b/output/heron/059.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/060.svg b/output/heron/060.svg
new file mode 100644
index 0000000..1bd5345
--- /dev/null
+++ b/output/heron/060.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/061.svg b/output/heron/061.svg
new file mode 100644
index 0000000..3cd398d
--- /dev/null
+++ b/output/heron/061.svg
@@ -0,0 +1,51 @@
+
+
\ No newline at end of file
diff --git a/output/heron/062.svg b/output/heron/062.svg
new file mode 100644
index 0000000..cc511a1
--- /dev/null
+++ b/output/heron/062.svg
@@ -0,0 +1,61 @@
+
+
\ No newline at end of file
diff --git a/output/heron/063.svg b/output/heron/063.svg
new file mode 100644
index 0000000..2f9559a
--- /dev/null
+++ b/output/heron/063.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/064.svg b/output/heron/064.svg
new file mode 100644
index 0000000..c78839c
--- /dev/null
+++ b/output/heron/064.svg
@@ -0,0 +1,63 @@
+
+
\ No newline at end of file
diff --git a/output/heron/065.svg b/output/heron/065.svg
new file mode 100644
index 0000000..b573e04
--- /dev/null
+++ b/output/heron/065.svg
@@ -0,0 +1,58 @@
+
+
\ No newline at end of file
diff --git a/output/heron/066.svg b/output/heron/066.svg
new file mode 100644
index 0000000..f4b4e30
--- /dev/null
+++ b/output/heron/066.svg
@@ -0,0 +1,60 @@
+
+
\ No newline at end of file
diff --git a/output/heron/067.svg b/output/heron/067.svg
new file mode 100644
index 0000000..e529ea0
--- /dev/null
+++ b/output/heron/067.svg
@@ -0,0 +1,58 @@
+
+
\ No newline at end of file
diff --git a/output/heron/068.svg b/output/heron/068.svg
new file mode 100644
index 0000000..aee7604
--- /dev/null
+++ b/output/heron/068.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/069.svg b/output/heron/069.svg
new file mode 100644
index 0000000..677a933
--- /dev/null
+++ b/output/heron/069.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/output/heron/070.svg b/output/heron/070.svg
new file mode 100644
index 0000000..0a71baf
--- /dev/null
+++ b/output/heron/070.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/071.svg b/output/heron/071.svg
new file mode 100644
index 0000000..1a6aa30
--- /dev/null
+++ b/output/heron/071.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/072.svg b/output/heron/072.svg
new file mode 100644
index 0000000..a2aa128
--- /dev/null
+++ b/output/heron/072.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/output/heron/073.svg b/output/heron/073.svg
new file mode 100644
index 0000000..3310258
--- /dev/null
+++ b/output/heron/073.svg
@@ -0,0 +1,55 @@
+
+
\ No newline at end of file
diff --git a/output/heron/074.svg b/output/heron/074.svg
new file mode 100644
index 0000000..e25b9b3
--- /dev/null
+++ b/output/heron/074.svg
@@ -0,0 +1,64 @@
+
+
\ No newline at end of file
diff --git a/output/heron/075.svg b/output/heron/075.svg
new file mode 100644
index 0000000..c31aae1
--- /dev/null
+++ b/output/heron/075.svg
@@ -0,0 +1,69 @@
+
+
\ No newline at end of file
diff --git a/output/heron/076.svg b/output/heron/076.svg
new file mode 100644
index 0000000..1c06969
--- /dev/null
+++ b/output/heron/076.svg
@@ -0,0 +1,62 @@
+
+
\ No newline at end of file
diff --git a/output/heron/077.svg b/output/heron/077.svg
new file mode 100644
index 0000000..42ad861
--- /dev/null
+++ b/output/heron/077.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/078.svg b/output/heron/078.svg
new file mode 100644
index 0000000..034ccde
--- /dev/null
+++ b/output/heron/078.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/079.svg b/output/heron/079.svg
new file mode 100644
index 0000000..c2a02be
--- /dev/null
+++ b/output/heron/079.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/080.svg b/output/heron/080.svg
new file mode 100644
index 0000000..0362f77
--- /dev/null
+++ b/output/heron/080.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/081.svg b/output/heron/081.svg
new file mode 100644
index 0000000..d5ddb4e
--- /dev/null
+++ b/output/heron/081.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/082.svg b/output/heron/082.svg
new file mode 100644
index 0000000..eca08ba
--- /dev/null
+++ b/output/heron/082.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/083.svg b/output/heron/083.svg
new file mode 100644
index 0000000..c75372b
--- /dev/null
+++ b/output/heron/083.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/084.svg b/output/heron/084.svg
new file mode 100644
index 0000000..cc39492
--- /dev/null
+++ b/output/heron/084.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/085.svg b/output/heron/085.svg
new file mode 100644
index 0000000..7ce5217
--- /dev/null
+++ b/output/heron/085.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/output/heron/086.svg b/output/heron/086.svg
new file mode 100644
index 0000000..28f8eac
--- /dev/null
+++ b/output/heron/086.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/087.svg b/output/heron/087.svg
new file mode 100644
index 0000000..6238d30
--- /dev/null
+++ b/output/heron/087.svg
@@ -0,0 +1,54 @@
+
+
\ No newline at end of file
diff --git a/output/heron/088.svg b/output/heron/088.svg
new file mode 100644
index 0000000..060bec0
--- /dev/null
+++ b/output/heron/088.svg
@@ -0,0 +1,54 @@
+
+
\ No newline at end of file
diff --git a/output/heron/089.svg b/output/heron/089.svg
new file mode 100644
index 0000000..f421eed
--- /dev/null
+++ b/output/heron/089.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/090.svg b/output/heron/090.svg
new file mode 100644
index 0000000..7c964f4
--- /dev/null
+++ b/output/heron/090.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/091.svg b/output/heron/091.svg
new file mode 100644
index 0000000..571ccec
--- /dev/null
+++ b/output/heron/091.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/092.svg b/output/heron/092.svg
new file mode 100644
index 0000000..1715bb5
--- /dev/null
+++ b/output/heron/092.svg
@@ -0,0 +1,51 @@
+
+
\ No newline at end of file
diff --git a/output/heron/093.svg b/output/heron/093.svg
new file mode 100644
index 0000000..eb6e829
--- /dev/null
+++ b/output/heron/093.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/094.svg b/output/heron/094.svg
new file mode 100644
index 0000000..7e4a48d
--- /dev/null
+++ b/output/heron/094.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/095.svg b/output/heron/095.svg
new file mode 100644
index 0000000..bd5d0dd
--- /dev/null
+++ b/output/heron/095.svg
@@ -0,0 +1,40 @@
+
+
\ No newline at end of file
diff --git a/output/heron/096.svg b/output/heron/096.svg
new file mode 100644
index 0000000..a0d26e2
--- /dev/null
+++ b/output/heron/096.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/output/heron/097.svg b/output/heron/097.svg
new file mode 100644
index 0000000..503814e
--- /dev/null
+++ b/output/heron/097.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/098.svg b/output/heron/098.svg
new file mode 100644
index 0000000..b160bbe
--- /dev/null
+++ b/output/heron/098.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/099.svg b/output/heron/099.svg
new file mode 100644
index 0000000..f7b9f12
--- /dev/null
+++ b/output/heron/099.svg
@@ -0,0 +1,40 @@
+
+
\ No newline at end of file
diff --git a/output/heron/100.svg b/output/heron/100.svg
new file mode 100644
index 0000000..eab1e07
--- /dev/null
+++ b/output/heron/100.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/output/heron/101.svg b/output/heron/101.svg
new file mode 100644
index 0000000..95c34c8
--- /dev/null
+++ b/output/heron/101.svg
@@ -0,0 +1,40 @@
+
+
\ No newline at end of file
diff --git a/output/heron/102.svg b/output/heron/102.svg
new file mode 100644
index 0000000..620e2c6
--- /dev/null
+++ b/output/heron/102.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/src/card_types.py b/src/card_types.py
new file mode 100644
index 0000000..c5efcbb
--- /dev/null
+++ b/src/card_types.py
@@ -0,0 +1,48 @@
+from dataclasses import dataclass
+from typing import TypedDict
+
+
+@dataclass
+class Translation(TypedDict):
+ card_type: dict[str, str]
+ effects: dict[str, str]
+
+
+@dataclass
+class SkinData(TypedDict):
+ title: str
+ flavor_text_type: str | None
+ image_path: str
+
+
+@dataclass
+class SkinFile(TypedDict):
+ skin_name: str
+ cards: dict[str, SkinData]
+
+
+@dataclass
+class EffectType(TypedDict):
+ id: str
+ amount: str | None
+ faction: str | None
+
+
+@dataclass
+class Effect(TypedDict):
+ effect: str
+ amount: int
+ effect_type: str | EffectType | None
+
+
+@dataclass
+class Card(TypedDict):
+ id: int
+ name: str
+ role: str
+ effects: list[Effect] | None
+ faction: str
+ card_type: str
+ cost: int | None
+ guard: bool | None
+ defense: int | None
diff --git a/src/data/cards/pack1_base_deck.json b/src/data/cards/pack1_base_deck.json
new file mode 100644
index 0000000..9828e54
--- /dev/null
+++ b/src/data/cards/pack1_base_deck.json
@@ -0,0 +1,75 @@
+{
+ "cards": [
+ {
+ "id": 59,
+ "role": "personal",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Ruby",
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ }
+ ]
+ },
+ {
+ "id": 58,
+ "role": "personal",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Dagger",
+ "effects": [
+ {
+ "effect": "damage"
+ }
+ ]
+ },
+ {
+ "id": 57,
+ "role": "personal",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Shortsword",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "role": "personal",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Gold",
+ "init_amount": 7,
+ "effects": [
+ {
+ "effect": "gold"
+ }
+ ]
+ },
+ {
+ "id": 55,
+ "role": "fire_gem",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Fire Gem",
+ "cost": 2,
+ "init_amount": 16,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "suicide"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack1_base_guild.json b/src/data/cards/pack1_base_guild.json
new file mode 100644
index 0000000..9cb3c50
--- /dev/null
+++ b/src/data/cards/pack1_base_guild.json
@@ -0,0 +1,290 @@
+{
+ "cards": [
+ {
+ "id": 28,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "Street Thug",
+ "cost": 3,
+ "defense": 4,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "gold",
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 15,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "borg, ogre mercenary",
+ "cost": 6,
+ "defense": 6,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 16,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "bribe",
+ "cost": 3,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 3
+ },
+ {
+ "effect": "stack_next_action_bought",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 17,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "death threat",
+ "cost": 3,
+ "effects": [
+ {
+ "effect": "damage"
+ },
+ {
+ "effect": "draw"
+ },
+ {
+ "effect": "stun",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 18,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "deception",
+ "cost": 5,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "draw"
+ },
+ {
+ "effect": "play_next_card_bought",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 19,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "fire bomb",
+ "cost": 8,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 8
+ },
+ {
+ "effect": "stun"
+ },
+ {
+ "effect": "draw"
+ },
+ {
+ "effect": "damage",
+ "amount": 5,
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 20,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "tit job",
+ "cost": 4,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 7
+ },
+ {
+ "effect": "stun",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 21,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "intimidation",
+ "cost": 2,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 5
+ },
+ {
+ "effect": "gold",
+ "amount": 2,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 22,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "myros, guild mage",
+ "cost": 5,
+ "defense": 3,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 23,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "parov, the enforcer",
+ "cost": 5,
+ "defense": 5,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 24,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "profit",
+ "cost": 1,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 25,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "rake, master assassin",
+ "cost": 7,
+ "defense": 7,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "stun",
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 26,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "rasmus, the smuggler",
+ "cost": 4,
+ "defense": 5,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "stack_next_card_bought",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 27,
+ "role": "market",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "smash and grab",
+ "cost": 6,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 6
+ },
+ {
+ "effect": "restack_discarded_card"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack1_base_imperial.json b/src/data/cards/pack1_base_imperial.json
new file mode 100644
index 0000000..9c9cce0
--- /dev/null
+++ b/src/data/cards/pack1_base_imperial.json
@@ -0,0 +1,343 @@
+{
+ "cards": [
+ {
+ "id": 1,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Arkus, Imperial Dragon",
+ "cost": 8,
+ "defense": 6,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "draw",
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "damage",
+ "amount": 5,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "heal",
+ "amount": 6,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Close Ranks",
+ "cost": 3,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 5
+ },
+ {
+ "effect": "damage",
+ "amount": 2,
+ "per": "champion"
+ },
+ {
+ "effect": "heal",
+ "amount": 6,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Command",
+ "cost": 5,
+ "effects": [
+ {
+ "effect": "draw"
+ },
+ {
+ "effect": "damage",
+ "amount": 3
+ },
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "heal",
+ "amount": 4
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Darian , War Mage",
+ "cost": 4,
+ "defense": 5,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "heal",
+ "amount": 4,
+ "effect_type": "champion_action",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 5,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Domination",
+ "cost": 7,
+ "effects": [
+ {
+ "effect": "heal",
+ "amount": 6
+ },
+ {
+ "effect": "damage",
+ "amount": 6
+ },
+ {
+ "effect": "draw"
+ },
+ {
+ "effect": "prepare",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 6,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Cristov, the Just",
+ "cost": 5,
+ "defense": 5,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "heal",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 7,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Kraka, High Priest",
+ "cost": 6,
+ "defense": 6,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "heal",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "heal",
+ "amount": 2,
+ "effect_type": "faction_combo",
+ "per": "champion"
+ }
+ ]
+ },
+ {
+ "id": 8,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Man-at-Arms",
+ "cost": 3,
+ "defense": 4,
+ "guard": true,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "damage",
+ "per": "other_guard",
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 9,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Master Weyan",
+ "cost": 4,
+ "defense": 4,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "damage",
+ "per": "other_champion",
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 10,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Rally the Troops",
+ "cost": 4,
+ "effects": [
+ {
+ "effect": "heal",
+ "amount": 5
+ },
+ {
+ "effect": "damage",
+ "amount": 5
+ },
+ {
+ "effect": "prepare",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 11,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Recruit",
+ "cost": 2,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "heal",
+ "amount": 3
+ },
+ {
+ "effect": "heal",
+ "per": "champion"
+ },
+ {
+ "effect": "gold",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 12,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Tits Priest",
+ "cost": 2,
+ "defense": 3,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "gold",
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "heal",
+ "effect_type": "champion_action",
+ "mutex": 1,
+ "per": "champion"
+ }
+ ]
+ },
+ {
+ "id": 13,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Taxation",
+ "cost": 1,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "heal",
+ "amount": 6,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 14,
+ "role": "market",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Word of Power",
+ "cost": 6,
+ "effects": [
+ {
+ "effect": "draw",
+ "amount": 2
+ },
+ {
+ "effect": "heal",
+ "amount": 5,
+ "effect_type": "faction_combo"
+ },
+ {
+ "effect": "damage",
+ "amount": 5,
+ "effect_type": "suicide"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack1_base_necros.json b/src/data/cards/pack1_base_necros.json
new file mode 100644
index 0000000..97a8b66
--- /dev/null
+++ b/src/data/cards/pack1_base_necros.json
@@ -0,0 +1,298 @@
+{
+ "cards": [
+ {
+ "id": 38,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "Lys, the Unseen",
+ "cost": 6,
+ "defense": 5,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "sacrifice",
+ "effect_type": "champion_action",
+ "sub_effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": 29,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "Ass Priest",
+ "cost": 3,
+ "defense": 4,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "gold",
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "damage",
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 30,
+ "role": "market",
+ "card_type": "action",
+ "faction": "red",
+ "name": "dark energy",
+ "cost": 4,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 7
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 31,
+ "role": "market",
+ "card_type": "action",
+ "faction": "red",
+ "name": "dark reward",
+ "cost": 5,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 3
+ },
+ {
+ "effect": "sacrifice"
+ },
+ {
+ "effect": "damage",
+ "amount": 6,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 32,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "death cultist",
+ "cost": 2,
+ "defense": 3,
+ "guard": true,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 33,
+ "role": "market",
+ "card_type": "action",
+ "faction": "red",
+ "name": "death touch",
+ "cost": 1,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ },
+ {
+ "effect": "sacrifice"
+ },
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 34,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "rayla, endweaver",
+ "cost": 4,
+ "defense": 4,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 35,
+ "role": "market",
+ "card_type": "action",
+ "faction": "red",
+ "name": "influence",
+ "cost": 2,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 3
+ },
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 36,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "krythos, master vampire",
+ "cost": "7",
+ "defense": 6,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "sacrifice",
+ "effect_type": "champion_action",
+ "sub_effects": [
+ {
+ "effect": "damage",
+ "amount": 3
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": 37,
+ "role": "market",
+ "card_type": "action",
+ "faction": "red",
+ "name": "life drain",
+ "cost": 6,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 8
+ },
+ {
+ "effect": "sacrifice"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 39,
+ "role": "market",
+ "card_type": "action",
+ "faction": "red",
+ "name": "the rot",
+ "cost": 3,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4
+ },
+ {
+ "effect": "sacrifice"
+ },
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 40,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "tyrannor, the devourer",
+ "cost": 8,
+ "defense": 6,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "sacrifice",
+ "times": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 41,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "varrick, the necromancer",
+ "cost": 5,
+ "defense": 3,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "restack_discarded_champion",
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack1_base_wild.json b/src/data/cards/pack1_base_wild.json
new file mode 100644
index 0000000..0139e26
--- /dev/null
+++ b/src/data/cards/pack1_base_wild.json
@@ -0,0 +1,291 @@
+{
+ "cards": [
+ {
+ "id": 42,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "broelyn, loreweaver",
+ "cost": 4,
+ "defense": 6,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "make_discard",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 43,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "cron, the berserker",
+ "cost": 6,
+ "defense": 6,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 5,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 44,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "dire wolf",
+ "cost": 5,
+ "defense": 5,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 45,
+ "role": "market",
+ "card_type": "action",
+ "faction": "green",
+ "name": "elven curse",
+ "cost": 3,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 6
+ },
+ {
+ "effect": "make_discard"
+ },
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 46,
+ "role": "market",
+ "card_type": "action",
+ "faction": "green",
+ "name": "elven gift",
+ "cost": 2,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ },
+ {
+ "effect": "draw_and_discard"
+ },
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 47,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "grak, storm giant",
+ "cost": 8,
+ "defense": 7,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 6,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw_and_discard",
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw_and_discard",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 48,
+ "role": "market",
+ "card_type": "action",
+ "faction": "green",
+ "name": "nature's bounty",
+ "cost": 4,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 4
+ },
+ {
+ "effect": "make_discard",
+ "effect_type": "faction_combo"
+ },
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 49,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "orc grunt",
+ "cost": 3,
+ "defense": 3,
+ "guard": true,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 50,
+ "role": "market",
+ "card_type": "action",
+ "faction": "green",
+ "name": "rampage",
+ "cost": 6,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 6
+ },
+ {
+ "effect": "draw_and_discard",
+ "times": 2
+ }
+ ]
+ },
+ {
+ "id": 51,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "torgen rocksplitter",
+ "cost": 7,
+ "defense": 7,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "make_discard",
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 52,
+ "role": "market",
+ "card_type": "action",
+ "faction": "green",
+ "name": "spark",
+ "cost": 1,
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3
+ },
+ {
+ "effect": "make_discard"
+ },
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 53,
+ "role": "market",
+ "card_type": "action",
+ "faction": "green",
+ "name": "wolf form",
+ "cost": 5,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 8
+ },
+ {
+ "effect": "make_discard"
+ },
+ {
+ "effect": "make_discard",
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 54,
+ "role": "market",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "wolf shaman",
+ "cost": 2,
+ "defense": 4,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "damage",
+ "amount": 1,
+ "per": "other_card_of_same_faction",
+ "effect_type": "champion_action"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack2_journeys_hunters.json b/src/data/cards/pack2_journeys_hunters.json
new file mode 100644
index 0000000..96b96ea
--- /dev/null
+++ b/src/data/cards/pack2_journeys_hunters.json
@@ -0,0 +1,172 @@
+{
+ "cards": [
+ {
+ "id": 68,
+ "role": "hunter",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Confiscate",
+ "cost": 3,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "buy_for_free",
+ "amount": 4
+ },
+ {
+ "effect": "heal",
+ "amount": 6,
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 69,
+ "role": "hunter",
+ "card_type": "action",
+ "faction": "red",
+ "name": "Demonic Cloud",
+ "cost": 7,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 7
+ },
+ {
+ "effect": "damage_all_champions",
+ "amount": 4
+ },
+ {
+ "effect": "draw"
+ },
+ {
+ "effect": "sacrifice",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 70,
+ "role": "hunter",
+ "card_type": "action",
+ "faction": "green",
+ "name": "Pack’s Fury",
+ "cost": 7,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 7
+ },
+ {
+ "effect": "discard_x_and_draw_x"
+ }
+ ]
+ },
+ {
+ "id": 71,
+ "role": "hunter",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "Thrash",
+ "cost": 2,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4,
+ "mutex": 1
+ },
+ {
+ "effect": "stun",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 72,
+ "role": "hunter",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Andor, the Valiant",
+ "cost": 6,
+ "defense": 5,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "prepare_another_champion",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 73,
+ "role": "hunter",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "Fettered Imp",
+ "cost": 2,
+ "defense": 5,
+ "guard": true,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "sacrifice",
+ "effect_type": "champion_action"
+ }
+ ]
+ },
+ {
+ "id": 74,
+ "role": "hunter",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "Lenka, the Hunter",
+ "cost": 5,
+ "defense": 5,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 4,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "stun",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 75,
+ "role": "hunter",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "Pathfinder",
+ "cost": 3,
+ "defense": 4,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action"
+ },
+ {
+ "effect": "gold",
+ "amount": 2,
+ "effect_type": "faction_combo"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack2_journeys_travelers.json b/src/data/cards/pack2_journeys_travelers.json
new file mode 100644
index 0000000..9fb66b6
--- /dev/null
+++ b/src/data/cards/pack2_journeys_travelers.json
@@ -0,0 +1,185 @@
+{
+ "cards": [
+ {
+ "id": 60,
+ "role": "traveler",
+ "card_type": "action",
+ "faction": "blue",
+ "name": "Bounty Collection",
+ "cost": 7,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 3
+ },
+ {
+ "effect": "play_next_card_bought"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "faction_combo"
+ }
+ ]
+ },
+ {
+ "id": 61,
+ "role": "traveler",
+ "card_type": "action",
+ "faction": "green",
+ "name": "Daring Escape",
+ "cost": 3,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "make_discard"
+ },
+ {
+ "effect": "restack_discarded_card"
+ },
+ {
+ "effect": "draw",
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 62,
+ "role": "traveler",
+ "card_type": "action",
+ "faction": "yellow",
+ "name": "Fearless Charge",
+ "cost": 8,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 5
+ },
+ {
+ "effect": "heal",
+ "amount": 5
+ },
+ {
+ "effect": "draw",
+ "amount": 2
+ },
+ {
+ "effect": "prepare_all_champions",
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 63,
+ "role": "traveler",
+ "card_type": "action",
+ "faction": "red",
+ "name": "Sway",
+ "cost": 3,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 3
+ },
+ {
+ "effect": "cheaper_champions_passive"
+ },
+ {
+ "effect": "control_opposing_champion_passive",
+ "effect_type": "suicide"
+ }
+ ]
+ },
+ {
+ "id": 64,
+ "role": "traveler",
+ "card_type": "champion",
+ "faction": "blue",
+ "name": "Con Artist",
+ "cost": 2,
+ "defense": 2,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "gold",
+ "per": "stunned_champion",
+ "effect_type": "champion_action",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 65,
+ "role": "traveler",
+ "card_type": "champion",
+ "faction": "red",
+ "name": "Olara, the Slayer",
+ "cost": 4,
+ "defense": 5,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2,
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "damage_all_champions",
+ "amount": 2,
+ "effect_type": "champion_action",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 66,
+ "role": "traveler",
+ "card_type": "champion",
+ "faction": "green",
+ "name": "Pelleas, the Seeker",
+ "cost": 5,
+ "defense": 4,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3,
+ "effect_type": "champion_action",
+ "mutex": 1
+ },
+ {
+ "effect": "restack_discarded_action",
+ "effect_type": "champion_action",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 67,
+ "role": "traveler",
+ "card_type": "champion",
+ "faction": "yellow",
+ "name": "Veteran Squire",
+ "cost": 3,
+ "defense": 3,
+ "guard": false,
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "per": "champion_of_same_faction",
+ "effect_type": "champion_action"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack3_character_cleric.json b/src/data/cards/pack3_character_cleric.json
new file mode 100644
index 0000000..a3f0b61
--- /dev/null
+++ b/src/data/cards/pack3_character_cleric.json
@@ -0,0 +1,97 @@
+{
+ "cards": [
+ {
+ "id": 87,
+ "role": "cleric",
+ "card_type": "champion",
+ "faction": "base",
+ "name": "Follower A",
+ "defense": 1,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage"
+ }
+ ]
+ },
+ {
+ "id": 88,
+ "role": "cleric",
+ "card_type": "champion",
+ "faction": "base",
+ "name": "Follower B",
+ "defense": 1,
+ "guard": true,
+ "effects": [
+ {
+ "effect": "damage"
+ }
+ ]
+ },
+ {
+ "id": 89,
+ "role": "cleric",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Spiked Mace",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ }
+ ]
+ },
+ {
+ "id": 90,
+ "role": "cleric",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Prayer Beads",
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2,
+ "sub_effects": [
+ {
+ "effect": "heal",
+ "amount": 5,
+ "effect_type": {
+ "id": "champion_amount",
+ "amount": 2
+ }
+ }
+ ],
+ "mutex": 1
+ },
+ {
+ "effect": "heal",
+ "amount": 5,
+ "sub_effects": [
+ {
+ "effect": "gold",
+ "amount": 2,
+ "effect_type": {
+ "id": "champion_amount",
+ "amount": 2
+ }
+ }
+ ],
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "role": "cleric",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Gold",
+ "init_amount": 6,
+ "effects": [
+ {
+ "effect": "gold"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack3_character_fighter.json b/src/data/cards/pack3_character_fighter.json
new file mode 100644
index 0000000..7078606
--- /dev/null
+++ b/src/data/cards/pack3_character_fighter.json
@@ -0,0 +1,72 @@
+{
+ "cards": [
+ {
+ "id": 84,
+ "role": "fighter",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Longsword",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3
+ }
+ ]
+ },
+ {
+ "id": 85,
+ "role": "fighter",
+ "card_type": "champion",
+ "faction": "base",
+ "name": "Shield Bearer",
+ "defense": 3,
+ "guard": true
+ },
+ {
+ "id": 86,
+ "role": "fighter",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Throwing Axe",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ },
+ {
+ "effect": "draw",
+ "effect_type": {
+ "id": "total_damage",
+ "amount": 7
+ }
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "role": "fighter",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Gold",
+ "init_amount": 1,
+ "effects": [
+ {
+ "effect": "gold"
+ }
+ ]
+ },
+ {
+ "id": 59,
+ "role": "fighter",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Ruby",
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack3_character_ranger.json b/src/data/cards/pack3_character_ranger.json
new file mode 100644
index 0000000..af3e259
--- /dev/null
+++ b/src/data/cards/pack3_character_ranger.json
@@ -0,0 +1,78 @@
+{
+ "cards": [
+ {
+ "id": 81,
+ "role": "ranger",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Black Arrow",
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage"
+ },
+ {
+ "effect": "draw",
+ "effect_type": {
+ "id": "card_amount",
+ "card_id": 83
+ }
+ }
+ ]
+ },
+ {
+ "id": 82,
+ "role": "ranger",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Horn of Calling",
+ "effects": [
+ {
+ "effect": "gold"
+ },
+ {
+ "effect": "cheaper_champion"
+ }
+ ]
+ },
+ {
+ "id": 83,
+ "role": "ranger",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Hunting Bow",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "role": "ranger",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Gold",
+ "init_amount": 5,
+ "effects": [
+ {
+ "effect": "gold"
+ }
+ ]
+ },
+ {
+ "id": 59,
+ "role": "ranger",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Ruby",
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack3_character_thief.json b/src/data/cards/pack3_character_thief.json
new file mode 100644
index 0000000..9cb1bf7
--- /dev/null
+++ b/src/data/cards/pack3_character_thief.json
@@ -0,0 +1,49 @@
+{
+ "cards": [
+ {
+ "id": 80,
+ "role": "thief",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Throwing Knife",
+ "init_amount": 3,
+ "effects": [
+ {
+ "effect": "damage"
+ },
+ {
+ "effect": "damage",
+ "amount": 2,
+ "per": "other_knife_played"
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "role": "thief",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Gold",
+ "init_amount": 5,
+ "effects": [
+ {
+ "effect": "gold"
+ }
+ ]
+ },
+ {
+ "id": 59,
+ "role": "thief",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Ruby",
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack3_character_wizard.json b/src/data/cards/pack3_character_wizard.json
new file mode 100644
index 0000000..b96a9e8
--- /dev/null
+++ b/src/data/cards/pack3_character_wizard.json
@@ -0,0 +1,88 @@
+{
+ "cards": [
+ {
+ "id": 76,
+ "role": "wizard",
+ "card_type": "champion",
+ "faction": "base",
+ "name": "Cat Familiar",
+ "defense": 2,
+ "guard": false,
+ "effects": [
+ {
+ "effect": "damage",
+ "mutex": 1
+ },
+ {
+ "effect": "gold",
+ "mutex": 1
+ },
+ {
+ "effect": "heal",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 77,
+ "role": "wizard",
+ "card_type": "action",
+ "faction": "base",
+ "name": "Ignite",
+ "init_amount": 2,
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ }
+ ]
+ },
+ {
+ "id": 78,
+ "role": "wizard",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Spell Components",
+ "effects": [
+ {
+ "effect": "gold"
+ },
+ {
+ "effect": "cheaper_action"
+ }
+ ]
+ },
+ {
+ "id": 79,
+ "role": "wizard",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Fire Staff",
+ "effects": [
+ {
+ "effect": "damage"
+ },
+ {
+ "effect": "draw",
+ "effect_type": {
+ "id": "action_amount",
+ "amount": 2
+ }
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "role": "wizard",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Gold",
+ "init_amount": 5,
+ "effects": [
+ {
+ "effect": "gold"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards/pack4_ancestry.json b/src/data/cards/pack4_ancestry.json
new file mode 100644
index 0000000..52e23f9
--- /dev/null
+++ b/src/data/cards/pack4_ancestry.json
@@ -0,0 +1,188 @@
+{
+ "cards": [
+ {
+ "id": 91,
+ "role": "half-demon",
+ "card_type": "action",
+ "faction": "red",
+ "name": "Demon Blood",
+ "effects": [
+ {
+ "effect": "gold",
+ "mutex": 1
+ },
+ {
+ "effect": "sacrifice",
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 92,
+ "role": "half-demon",
+ "card_type": "action",
+ "faction": "base",
+ "name": "Demonic Strength",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2
+ },
+ {
+ "effect": "keep_in_hand",
+ "effect_type": {
+ "id": "faction_combo",
+ "faction": "red"
+ }
+ }
+ ]
+ },
+ {
+ "id": 93,
+ "role": "dwarf",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Hammer",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3
+ }
+ ]
+ },
+ {
+ "id": 94,
+ "role": "dwarf",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Pick",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 2,
+ "mutex": 1
+ },
+ {
+ "effect": "buy_gem_for_free",
+ "amount": 2,
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 95,
+ "role": "elf",
+ "card_type": "action",
+ "faction": "base",
+ "name": "Elven Grace",
+ "effects": [
+ {
+ "effect": "cheaper_skills_passive"
+ },
+ {
+ "effect": "draw"
+ }
+ ]
+ },
+ {
+ "id": 96,
+ "role": "elf",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Sunstone Brooch",
+ "effects": [
+ {
+ "effect": "gold",
+ "mutex": 1
+ },
+ {
+ "effect": "heal",
+ "amount": 2,
+ "mutex": 1
+ }
+ ]
+ },
+ {
+ "id": 97,
+ "role": "ogre",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Shiny Rock",
+ "effects": [
+ {
+ "effect": "gold",
+ "amount": 2
+ }
+ ]
+ },
+ {
+ "id": 98,
+ "role": "ogre",
+ "card_type": "item",
+ "faction": "base",
+ "name": "War Club",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 5
+ }
+ ]
+ },
+ {
+ "id": 99,
+ "role": "orc",
+ "card_type": "action",
+ "faction": "base",
+ "name": "Bully",
+ "effects": [
+ {
+ "effect": "buy_for_free",
+ "amount": 3
+ }
+ ]
+ },
+ {
+ "id": 100,
+ "role": "orc",
+ "card_type": "item",
+ "faction": "base",
+ "name": "Ragged Blade",
+ "effects": [
+ {
+ "effect": "damage",
+ "amount": 3
+ }
+ ]
+ },
+ {
+ "id": 101,
+ "role": "smallfolk",
+ "card_type": "action",
+ "faction": "base",
+ "name": "Burgle",
+ "effects": [
+ {
+ "effect": "cheaper_card_if_higher_price"
+ },
+ {
+ "effect": "draw"
+ }
+ ]
+ },
+ {
+ "id": 102,
+ "role": "smallfolk",
+ "card_type": "action",
+ "faction": "base",
+ "name": "Friendly Banter",
+ "effects": [
+ {
+ "effect": "gold"
+ },
+ {
+ "effect": "pick_faction"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/cards_data.json b/src/data/cards_data.json
deleted file mode 100644
index 55a841d..0000000
--- a/src/data/cards_data.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "cards": [
- {
- "id": 1,
- "role": "market",
- "card_type": "champion",
- "faction": "yellow",
- "name": "Arkus, Imperial Dragon",
- "cost": 8,
- "defense": 6,
- "guard": true,
- "init_amount": 1,
- "effects": [
- {
- "effect": "draw",
- "amount": 1,
- "effect_type": "champion_action"
- },
- {
- "effect": "damage",
- "amount": 5,
- "effect_type": "champion_action"
- },
- {
- "effect": "heal",
- "amount": 6,
- "effect_type": "faction_combo"
- }
- ]
- },
- {
- "id": 13,
- "role": "market",
- "card_type": "action",
- "faction": "yellow",
- "name": "Taxation",
- "cost": 1,
- "init_amount": 3,
- "effects": [
- {
- "effect": "gold",
- "amount": 2
- },
- {
- "effect": "heal",
- "amount": 6,
- "effect_type": "faction_combo"
- }
- ]
- },
- {
- "id": 10,
- "role": "market",
- "card_type": "action",
- "faction": "yellow",
- "name": "Rally the Troops",
- "cost": 4,
- "init_amount": 1,
- "effects": [
- {
- "effect": "heal",
- "amount": 5
- },
- {
- "effect": "damage",
- "amount": 5
- },
- {
- "effect": "prepare",
- "amount": 1,
- "effect_type": "faction_combo"
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/src/data/heron_skin.json b/src/data/heron_skin.json
index cff831e..b6f3a59 100644
--- a/src/data/heron_skin.json
+++ b/src/data/heron_skin.json
@@ -1,15 +1,18 @@
{
"skin_name": "heron",
- "10": {
- "title": "Rallier les Troupes",
- "flavor_text_type": "Charme",
- "image_path": "../../img/skins/heron/010.png"
- },
- "13": {
- "title": "Caprisun",
- "flavor_text_type": "20cl",
- "image_path": "lancersiz3.png"
+ "cards":{
+ "10": {
+ "title": "Rallier les Troupes",
+ "flavor_text_type": "Charme",
+ "image_path": "../../img/skins/heron/010.png"
+ },
+ "13": {
+ "title": "Caprisun",
+ "flavor_text_type": "20cl",
+ "image_path": "lancersiz3.png"
+ }
}
+
}
\ No newline at end of file
diff --git a/src/data/translation_fr.json b/src/data/translation_fr.json
index 90b2946..a3e62e4 100644
--- a/src/data/translation_fr.json
+++ b/src/data/translation_fr.json
@@ -4,7 +4,14 @@
"champion":"Champion"
},
"effects":{
- "draw":"Piochez une carte"
+ "draw":"Piochez une carte.",
+ "stun":"Assomez le champion ciblé.",
+ "stack_next_card_bought":"Mettez la prochaine carte dont vous faites l'acquisition\nau dessus de votre pioche.",
+ "sacrifice":"Vous pouvez sacrifier une carte de votre main ou de votre défausse.",
+ "restack_discarded_champion":"Mettez un champion de votre défausse au dessus de votre pioche.",
+ "make_discard":"L'adversaire ciblé se défausse d'une carte",
+ "draw_and_discard":"Vous pouvez piocher une carte.\nSi vous faites ainsi, défaussez vous d'une carte.",
+ "play_next_card_bought":"Mettez dans votre main la prochaine carte dont vous faites l'acquisition.",
}
}
\ No newline at end of file
diff --git a/src/draw_functions.py.old b/src/draw_functions.old.py
similarity index 100%
rename from src/draw_functions.py.old
rename to src/draw_functions.old.py
diff --git a/src/draw_functions.py b/src/draw_functions.py
index 274475d..4ae346e 100644
--- a/src/draw_functions.py
+++ b/src/draw_functions.py
@@ -1,29 +1,338 @@
-from typing import List
from math import sin, cos, pi
import drawsvg as dw
import json
+from itertools import groupby
+
+from card_types import Card, Effect, Translation
+
stats_radius = 20
+effect_text_size = 14
-circle_icon = dw.Circle(cx=0, cy=0, r=stats_radius)
+with open("src/data/translation_fr.json", encoding="utf-8") as f:
+ translation_fr: Translation = json.load(f)
-with open('src/data/translation_fr.json', encoding="utf-8") as f:
- translation_fr: dict = json.load(f)
-def is_base_effect(array: dict):
- return not 'effect_type' in array.keys() or array['effect_type'] == 'champion_action'
+def is_base_effect(effect: Effect):
+ return not "effect_type" in effect or effect["effect_type"] == "champion_action"
-def create_icon(amount: int, fill_circle: str, fill_text: str = "black"):
+
+def create_icon(
+ amount: int,
+ fill_circle: str,
+ fill_text: str = "black",
+ radius: float = stats_radius,
+):
group = dw.Group()
- group.append(dw.Use(circle_icon, fill=fill_circle,x=0,y=0))
- group.append(dw.Text(str(amount), x=0, y=9, text_anchor="middle", fill=fill_text, font_size=24, font_weight="bold", font_family='Helvetica'))
+ group.append(dw.Circle(cx=0, cy=0, r=radius, fill=fill_circle, x=0, y=0))
+ group.append(
+ dw.Text(
+ str(amount),
+ x=0,
+ y=9,
+ text_anchor="middle",
+ fill=fill_text,
+ font_size=24,
+ font_weight="bold",
+ font_family="Helvetica",
+ )
+ )
return group
-def create_damage_icon(amount: int):
- return create_icon(amount, "red", "white")
-def create_heal_icon(amount: int):
- return create_icon(amount, "green")
+def create_damage_icon(amount: int, radius: float = stats_radius):
+ return create_icon(amount, radius=radius, fill_circle="red", fill_text="white")
-def create_gold_icon(amount: int):
- return create_icon(amount, "yellow")
\ No newline at end of file
+
+def create_heal_icon(amount: int, radius: float = stats_radius):
+ return create_icon(amount, radius=radius, fill_circle="green", fill_text="white")
+
+
+def create_gold_icon(amount: int, radius: float = stats_radius):
+ return create_icon(amount, radius=radius, fill_circle="yellow")
+
+
+def create_pentagon(cx: int, cy: int, radius: int):
+ points: list[float] = []
+ for i in range(5):
+ x = cx + radius * cos(2 * pi * i / 5 + (pi / 2))
+ y = cy + radius * sin(2 * pi * i / 5 + (pi / 2))
+ points.append(x)
+ points.append(y)
+ return points
+
+
+def draw_champion_shield(card_data: Card, border_width_x: int):
+ group = dw.Group(id="champion_shield")
+ pentagon = dw.Lines(
+ *create_pentagon(cx=border_width_x - 15, cy=-30, radius=28),
+ close=True,
+ stroke_width=2,
+ )
+ defense_text = dw.Text(
+ str(card_data["defense"]),
+ font_size="28px",
+ font_weight="bold",
+ font_family="Helvetica",
+ text_anchor="middle",
+ x=border_width_x - 15,
+ y=-20,
+ )
+ if not card_data["guard"]:
+ group.append(
+ dw.Use(
+ pentagon,
+ 0,
+ 0,
+ fill="darkgrey",
+ stroke="#eee",
+ )
+ )
+
+ group.append(dw.Use(defense_text, 0, 0, fill="black"))
+
+ else:
+ group.append(
+ dw.Use(
+ pentagon,
+ 0,
+ 0,
+ fill="black",
+ stroke="lightgrey",
+ )
+ )
+ group.append(
+ dw.Rectangle(
+ x=border_width_x - 40,
+ y=-72,
+ width=49,
+ height=17,
+ fill="black",
+ stroke="lightgrey",
+ stroke_width=2,
+ )
+ )
+ group.append(
+ dw.Text(
+ "Garde",
+ x=border_width_x - 15,
+ y=-59,
+ text_anchor="middle",
+ fill="white",
+ font_size="12px",
+ font_weight="bold",
+ font_family="Helvetica",
+ )
+ )
+
+ group.append(dw.Use(defense_text, 0, 0, fill="white"))
+ return group
+
+
+def create_champion_action_icon():
+ pass
+ # if card_data.card_type == "champion":
+ # row_1_icon_x = border_width_x + 35
+ # dwg.add(
+ # dwg.circle(
+ # center=(row_1_icon_x + 1, row_1_base_y + 20 + 1), r=15, fill="#111"
+ # )
+ # )
+ # dwg.add(dwg.circle(center=(row_1_icon_x, row_1_base_y + 20), r=15, fill="#555"))
+
+
+resourceIcons = {
+ "gold": create_gold_icon,
+ "heal": create_heal_icon,
+ "damage": create_damage_icon,
+}
+
+
+def create_effect_row(effects: list[Effect], type: str, height: int, width: int):
+ group = dw.Group()
+ if type == "faction_combo":
+ group.append(
+ dw.Circle(
+ cx=35,
+ cy=height / 2,
+ r=15,
+ fill="url(#grad2)",
+ filter="url(#drop-shadow)",
+ )
+ )
+ elif type == "suicide":
+ group.append(
+ dw.Circle(
+ cx=35,
+ cy=height / 2,
+ r=15,
+ fill="black",
+ filter="url(#drop-shadow)",
+ )
+ )
+
+ elif type == "champion_action":
+ group.append(
+ dw.Circle(
+ cx=35,
+ cy=height / 2,
+ r=15,
+ fill="gray",
+ filter="url(#drop-shadow)",
+ )
+ )
+ effect_with_icons = list(
+ filter(lambda x: x.get("effect") in resourceIcons, effects)
+ )
+ effect_with_text = list(
+ filter(lambda x: x.get("effect") not in resourceIcons, effects)
+ )
+
+ text_y_pos = height - effect_text_size / 2
+ if len(effect_with_icons) == 0:
+ text_y_pos = height / 2
+
+ icon_y_pos = (height / 2) - effect_text_size / 2
+
+ if len(effect_with_text) == 0:
+ icon_y_pos = height / 2
+
+ effect_text = ""
+
+ for e in effect_with_text:
+ if effect_text != "":
+ effect_text += " "
+ effect_text += translation_fr.get("effects").get(
+ e.get("effect"), e.get("effect")
+ )
+
+ group.append(
+ dw.Text(
+ effect_text,
+ x=width / 2,
+ y=text_y_pos,
+ text_anchor="middle",
+ fill="black",
+ font_size=effect_text_size,
+ font_family="Helvetica",
+ )
+ )
+
+ icon_radius = min(height / 3, stats_radius)
+ for [i, e] in enumerate(effect_with_icons):
+ f = resourceIcons.get(e.get("effect"))
+ if f is not None:
+ group.append(
+ dw.Use(
+ f(int(e.get("amount", 1)), radius=icon_radius),
+ (width / 2)
+ - ((len(effect_with_icons) - 1) * icon_radius * 1.5)
+ + (i * icon_radius * 3),
+ icon_y_pos,
+ )
+ )
+
+ return group
+
+
+def get_effect_type(effect: Effect):
+ effect_type = effect.get("effect_type")
+ if type(effect_type) is str:
+ return effect_type
+ if type(effect_type) is dict:
+ return effect_type.get("id")
+ return ""
+
+
+def create_effects(effects: list[Effect], height: int, width: int):
+ group = dw.Group(id="effects")
+ grouped_effects = {
+ k: list(g)
+ for k, g in groupby(
+ sorted(effects, key=lambda x: get_effect_type(x)),
+ lambda x: get_effect_type(x),
+ )
+ }
+ effect_types = list(grouped_effects.keys())
+
+ if len(grouped_effects) == 1:
+ group.append(
+ dw.Use(
+ create_effect_row(
+ grouped_effects[effect_types[0]], effect_types[0], height, width
+ ),
+ 0,
+ 0,
+ )
+ )
+ if len(grouped_effects) == 2:
+ group.append(
+ dw.Line(sx=10, sy=80, ex=width - 10, ey=80, stroke="black", stroke_width=1)
+ )
+ group.append(
+ dw.Use(
+ create_effect_row(
+ grouped_effects[effect_types[0]], effect_types[0], 80, width
+ ),
+ 0,
+ 0,
+ )
+ )
+
+ group.append(
+ dw.Use(
+ create_effect_row(
+ grouped_effects[effect_types[1]],
+ effect_types[1],
+ height - 80,
+ width,
+ ),
+ 0,
+ 80,
+ )
+ )
+
+ if len(grouped_effects) == 3:
+ group.append(
+ dw.Line(sx=10, sy=45, ex=width - 10, ey=45, stroke="black", stroke_width=1)
+ )
+ group.append(
+ dw.Line(sx=10, sy=90, ex=width - 10, ey=90, stroke="black", stroke_width=1)
+ )
+ group.append(
+ dw.Use(
+ create_effect_row(
+ grouped_effects[effect_types[0]], effect_types[0], 45, width
+ ),
+ 0,
+ 0,
+ )
+ )
+
+ group.append(
+ dw.Use(
+ create_effect_row(
+ grouped_effects[effect_types[1]],
+ effect_types[1],
+ 45,
+ width,
+ ),
+ 0,
+ 45,
+ )
+ )
+
+ group.append(
+ dw.Use(
+ create_effect_row(
+ grouped_effects[effect_types[1]],
+ effect_types[2],
+ 45,
+ width,
+ ),
+ 0,
+ 90,
+ )
+ )
+
+ return group
diff --git a/src/generate_cards_mvp.py b/src/generate_cards_mvp.py
index 70869c0..06aa7b3 100644
--- a/src/generate_cards_mvp.py
+++ b/src/generate_cards_mvp.py
@@ -1,34 +1,40 @@
import drawsvg as dw
import json
-from typing import List
import os
-from draw_functions import create_gold_icon
+from typing import cast
+from pathlib import Path
+from draw_functions import create_gold_icon, create_effects, draw_champion_shield
+from card_types import Card, SkinData, SkinFile, Translation
+
+from drawsvg.drawing import Drawing
with open("src/data/translation_fr.json", encoding="utf-8") as f:
- translation_fr: dict = json.load(f)
-
+ translation_fr: Translation = json.load(f)
with open("src/data/heron_skin.json", encoding="utf-8") as f:
- all_skin_data: dict = json.load(f)
+ all_skin_data: SkinFile = json.load(f)
+cards: list[Card] = []
+for p in Path('src/data/cards').glob('*.json'):
+ with open(p, encoding="utf-8") as f:
+ temp: list[Card] = json.load(f)["cards"]
+ cards.extend(temp)
# Params
x_width = 298
y_height = 417
border_width_x = 12
border_width_y = 17
+
+x_internal_width = x_width - (border_width_x*2)
+
border_upper_offset = 5
title_y_offset = 24
title_font_size = 19
title_font_size_small = 16
subtitle_font_size = 13
cost_right_offset = 38
-effect_text_size = 14
-row_1_base_y = 280
-row_2_base_y = 375
-row_1_to_2_separator_y = 345
-row_1_to_2_separator_shorten_by = 20
background_colors = {
"blue": "lightblue",
@@ -38,28 +44,22 @@ background_colors = {
"base": "lightgrey",
}
-gradient_colors = {"red": "red", "blue": "blue", "yellow": "yellow", "green": "green"}
-
-icon_colors = {"yellow": ["#ff9935", "#ffe744"]}
-
-with open("src/data/cards_data.json", encoding="utf-8") as f:
- cards: List = json.load(f)["cards"]
+gradient_colors = {"red": "red", "blue": "blue", "yellow": "yellow", "green": "green", "base":"gray"}
+icon_colors = {
+ "yellow": ["#ff9935", "#ffe744"],
+ "blue": ["#ff9935", "#ffe744"],
+ "red": ["#ff9935", "#ffe744"],
+ "green": ["#ff9935", "#ffe744"],
+ "base": ["#ff9935", "#ffe744"]
+ }
shadowFilter = dw.Filter(id="drop-shadow")
shadowFilter.append(dw.FilterItem("feDropShadow", dx=1, dy=1, stdDeviation=0))
# Draw faction icon
faction_icon = dw.Group(id="faction_icon")
-faction_icon.append(
- dw.Circle(
- cx=1,
- cy=1,
- r=20,
- fill="black",
- filter=shadowFilter
- )
-)
+faction_icon.append(dw.Circle(cx=1, cy=1, r=20, fill="black", filter=shadowFilter))
faction_icon.append(
dw.Circle(
cx=0,
@@ -72,64 +72,70 @@ faction_icon.append(
for card_data in cards:
# Get card skin data
try:
- card_skin_data = all_skin_data[str(card_data["id"])]
+ card_skin_data = all_skin_data["cards"][str(card_data["id"])]
except KeyError:
- print(
- "Missing skin data for card id:", card_data["id"], "using default skin data"
+ print("Missing skin data for card id:", card_data["id"], "using default skin data")
+ card_skin_data = SkinData(
+ title=card_data["name"],
+ image_path="../../img/missing.png",
+ flavor_text_type=None,
)
- card_skin_data = {
- "title": card_data["name"],
- "image_path": "../../img/missing.png",
- }
-
# Create a new SVG drawing
output_dir = "output/" + all_skin_data["skin_name"]
os.makedirs(output_dir, exist_ok=True)
- d = dw.Drawing(x_width, y_height)
+ d = Drawing(x_width, y_height)
d.append(shadowFilter)
# Define linear colored gradient
- gradient = dw.LinearGradient(0, 0, 1, 0, gradientUnits="objectBoundingBox",id="grad1")
+ gradient = dw.LinearGradient(
+ 0, 0, 1, 0, gradientUnits="objectBoundingBox", id="grad1"
+ )
gradient.add_stop(0, gradient_colors[card_data["faction"]], opacity=1)
gradient.add_stop(1, gradient_colors[card_data["faction"]], opacity=0)
- d.append(dw.Use(gradient, None, None))
+ d.append_def(gradient)
# Define linear colored gradient for faction icon
- gradient_faction_icon = dw.LinearGradient(0, 1, 0, 0, gradientUnits="objectBoundingBox",id="grad2")
+ gradient_faction_icon = dw.LinearGradient(
+ 0, 1, 0, 0, gradientUnits="objectBoundingBox", id="grad2"
+ )
gradient_faction_icon.add_stop(0, icon_colors[card_data["faction"]][0], opacity=1)
gradient_faction_icon.add_stop(1, icon_colors[card_data["faction"]][1], opacity=1)
- d.append(dw.Use(gradient_faction_icon, None, None))
+ d.append_def(gradient_faction_icon)
# Draw card background
- d.append(dw.Rectangle(0, 0, x_width, y_height, rx=15, ry=18, fill="black"))
- d.append(
+ background = dw.Group(id="background")
+ background.append(dw.Rectangle(0, 0, x_width, y_height, rx=15, ry=18, fill="black"))
+ background.append(
dw.Rectangle(
border_width_x,
border_width_y - border_upper_offset,
- x_width - border_width_x * 2,
+ x_internal_width,
y_height - border_width_y * 2 + border_upper_offset,
rx=0,
ry=0,
fill=background_colors[card_data["faction"]],
)
)
+ d.append(background)
# Draw title area
# dwg.add(dwg.rect(insert=(0, 0), size=(str(x_width) + 'px', '50px'), fill='white'))
+ title = dw.Group(id="title")
card_title = card_skin_data["title"]
- TEMP_TITLE_FONT_SIZE = title_font_size
if len(card_title) > 20:
- TEMP_TITLE_FONT_SIZE = title_font_size_small
- if len(card_title) > 23:
- TEMP_TITLE_FONT_SIZE = title_font_size_small - 2
- d.append(
+ temp_title_font_size = title_font_size_small
+ elif len(card_title) > 23:
+ temp_title_font_size = title_font_size_small - 2
+ else:
+ temp_title_font_size = title_font_size
+ title.append(
dw.Text(
card_title,
x=x_width / 2,
y=title_y_offset + border_width_y - border_upper_offset,
text_anchor="middle",
fill="black",
- font_size=TEMP_TITLE_FONT_SIZE,
+ font_size=temp_title_font_size,
font_weight="bold",
font_family="Helvetica",
)
@@ -138,9 +144,9 @@ for card_data in cards:
card_type_text = translation_fr["card_type"].get(
card_data["card_type"], card_data["card_type"]
)
- if "flavor_text_type" in card_skin_data.keys():
- card_type_text += ", " + card_skin_data["flavor_text_type"]
- d.append(
+ if card_skin_data.get("flavor_text_type") is not None:
+ card_type_text += ", " + str(card_skin_data["flavor_text_type"])
+ title.append(
dw.Text(
card_type_text,
font_size=subtitle_font_size,
@@ -151,86 +157,45 @@ for card_data in cards:
font_family="Helvetica",
)
)
+ d.append(title)
- d.append(dw.Use(faction_icon, border_width_x + 23 + 1,border_width_y - border_upper_offset + 20 + 4 + 1 ))
-
- # dwg.add(dwg.image(card_data['faction_icon'], insert=(x_width - 30 - 15, 30 - 15), size=(30, 30)))
- # Draw cost circle
-
- # dwg.add(
- # dwg.circle(
- # center=(x_width - cost_right_offset + 2, 19 + border_width_y + 2),
- # r=21,
- # fill="rgb(202, 129, 25)",
- # )
- # )
- # dwg.add(
- # dwg.circle(
- # center=(x_width - cost_right_offset, 19 + border_width_y),
- # r=20,
- # fill="yellow",
- # )
- # )
- # dwg.add(
- # dwg.text(
- # str(card_data["cost"]),
- # insert=(x_width - cost_right_offset, 26 + border_width_y),
- # text_anchor="middle",
- # fill="black",
- # font_size="24px",
- # font_weight="bold",
- # font_family="Helvetica",
- # )
- # )
- d.append(dw.Use(create_gold_icon(card_data["cost"]), x_width - cost_right_offset, 19 + border_width_y))
- d.save_svg(
- "output/"
- + all_skin_data["skin_name"]
- + "/"
- + str(card_data["id"]).zfill(3)
- + ".svg"
- )
- continue
- # Draw image area
- dwg.add(dwg.rect(insert=(0, 65), size=(str(x_width) + "px", "200px"), fill="black"))
- dwg.add(
- dwg.image(card_skin_data["image_path"], insert=(0, 65), size=(x_width, 200))
- )
-
- dwg.add(
- dwg.rect(
- insert=(border_width_x, 265),
- size=(str(30) + "px", str(y_height - 265 - border_width_y) + "px"),
- fill="url(#grad1)",
+ # Draw faction icon
+ d.append(
+ dw.Use(
+ faction_icon,
+ border_width_x + 23 + 1,
+ border_width_y - border_upper_offset + 20 + 4 + 1,
)
)
-
- # If champion, draw champion action icon
- if card_data["card_type"] == "champion":
- row_1_icon_x = border_width_x + 35
- dwg.add(
- dwg.circle(
- center=(row_1_icon_x + 1, row_1_base_y + 20 + 1), r=15, fill="#111"
+ # Draw card cost
+ if card_data.get("cost") is not None:
+ d.append(
+ dw.Use(
+ create_gold_icon(cast(int,card_data.get("cost"))),
+ x_width - cost_right_offset,
+ 19 + border_width_y,
)
)
- dwg.add(dwg.circle(center=(row_1_icon_x, row_1_base_y + 20), r=15, fill="#555"))
- draw_effects(
- dwg=dwg,
- card_effects=card_data["effects"],
- border_width_x=border_width_x,
- effect_text_size=effect_text_size,
- row_1_base_y=row_1_base_y,
- row_1_to_2_separator_shorten_by=row_1_to_2_separator_shorten_by,
- row_1_to_2_separator_y=row_1_to_2_separator_y,
- row_2_base_y=row_2_base_y,
- x_width=x_width,
- )
+ d.append(dw.Rectangle(x=0, y=65, width=x_width, height=200))
+ d.append(dw.Image(x=0, y=65, width=x_width, height=200,path=card_skin_data["image_path"]))
+
+
+ # Draw effects
+ effects = card_data.get("effects")
+ if effects is not None:
+ effects = create_effects(
+ effects=effects,
+ height=135,
+ width=x_internal_width
+ )
+ d.append(dw.Use(effects, border_width_x,265))
# If champion, draw champion shield with defense
if card_data["card_type"] == "champion":
- draw_champion_shield(dwg, card_data, x_width, y_height, border_width_x)
+ shield = draw_champion_shield(card_data, border_width_x)
+ d.append(dw.Use(shield,x_width-30, y_height))
# Save the SVG file
- dwg.save()
+ d.save_svg(f"output/{all_skin_data['skin_name']}/{str(card_data["id"]).zfill(3)}.svg")