1
0
Fork 0
mirror of https://github.com/ldericher/fftcgtool synced 2025-01-15 15:02:59 +00:00
fftcgtool/fftcg/ttsdeck.py

225 lines
6.4 KiB
Python
Raw Normal View History

2021-08-20 22:16:38 +00:00
from __future__ import annotations
2021-08-16 23:35:57 +00:00
import json
2021-09-03 01:40:45 +00:00
import logging
2021-08-23 14:00:17 +00:00
import os
2021-09-03 01:40:45 +00:00
import re
2021-08-16 23:35:57 +00:00
2021-08-20 22:16:38 +00:00
import requests
2021-08-16 23:35:57 +00:00
from .carddb import CardDB
2021-08-18 14:52:32 +00:00
from .cards import Cards
2021-08-16 23:35:57 +00:00
from .code import Code
from .language import Language
2021-08-23 14:00:17 +00:00
from .utils import CARD_BACK_URL, DECKS_DIR_NAME
2021-08-16 23:35:57 +00:00
2021-08-18 14:52:32 +00:00
class TTSDeck(Cards):
2021-09-03 00:46:04 +00:00
def __init__(self, codes: list[Code], name: str, description: str, face_down: bool):
2021-09-03 01:40:45 +00:00
logger = logging.getLogger(__name__)
2021-08-18 14:52:32 +00:00
super().__init__(name)
2021-08-18 11:49:34 +00:00
self.__description = description
2021-09-03 00:46:04 +00:00
self.__face_down = face_down
2021-08-18 11:49:34 +00:00
2021-08-18 15:38:58 +00:00
# get cards from carddb
2021-09-01 18:14:56 +00:00
carddb = CardDB()
2021-09-03 01:40:45 +00:00
# non-imported cards
codes_invalid = frozenset([
code
for code in codes
if code not in carddb
])
# show errors and remove non-imported cards
for code in codes_invalid:
logger.error(f"Code '{code}' not in CardDB, ignoring!")
while code in codes:
codes.remove(code)
# put existing cards into deck
2021-08-20 22:16:38 +00:00
self.extend([
carddb[code]
for code in codes
])
2021-08-18 14:52:32 +00:00
2021-09-03 02:57:34 +00:00
@property
def file_name(self) -> str:
return f"{super().file_name}.json"
2021-08-20 22:16:38 +00:00
__FFDECKS_API_URL = "https://ffdecks.com/api/deck"
2021-09-03 01:40:45 +00:00
__RE_FFDECKS_ID = re.compile(r"((https?://)?ffdecks\.com(/+api)?/+deck/+)?([0-9]+).*", flags=re.UNICODE)
2021-08-20 22:16:38 +00:00
@classmethod
def from_ffdecks_deck(cls, deck_id: str) -> TTSDeck:
2021-09-03 01:40:45 +00:00
logger = logging.getLogger(__name__)
# check deck id
match = TTSDeck.__RE_FFDECKS_ID.match(deck_id)
if match is None:
logger.error("Malformed Deck ID for FFDecks API!")
return cls([], "", "", True)
else:
# extract deck id from match
deck_id = match.groups()[3]
2021-09-03 00:46:04 +00:00
# api request
2021-08-20 22:16:38 +00:00
req = requests.get(TTSDeck.__FFDECKS_API_URL, params={"deck_id": deck_id})
2021-09-03 00:46:04 +00:00
2021-09-03 01:40:45 +00:00
if req.status_code != 200:
logger.error("Invalid Deck ID for FFDecks API!")
return cls([], "", "", True)
2021-09-03 00:46:04 +00:00
# pre-extract the used data
deck_cards = [{
"code": card["card"]["serial_number"],
"type": card["card"]["type"],
"cost": int(card["card"]["cost"]),
"count": int(card["quantity"]),
} for card in req.json()["cards"]]
# sort cards by type, then by cost
def by_type(data: dict[str, str | int]) -> int:
key_prios = {
"Forward": 1,
"Summon": 2,
"Monster": 3,
"Backup": 5,
}
if data["type"] in key_prios:
return key_prios[data["type"]]
else:
return 4
def by_cost(data: dict[str, str | int]) -> int:
return data["cost"]
deck_cards.sort(key=by_cost)
deck_cards.sort(key=by_type)
# ffdecks quirk: some full-art promos in database
replace_full_arts = {
# line format:
# full-art-id: normal id,
"PR-051": "11-083",
"PR-055": "11-062",
}
2021-09-03 01:12:22 +00:00
# replace with normal-art cards
2021-09-03 00:46:04 +00:00
for card in deck_cards:
if card["code"] in replace_full_arts:
card["code"] = replace_full_arts[card["code"]]
2021-08-20 22:16:38 +00:00
codes = [
2021-09-03 00:46:04 +00:00
# create list of code objects
Code(card["code"])
# for each card
for card in deck_cards
# repeat to meet count
for _ in range(card["count"])
2021-08-20 22:16:38 +00:00
]
2021-09-03 00:46:04 +00:00
# general metadata
name = f"{req.json()['name']}"
description = deck_id
# create deck object
return cls(codes, name, description, True)
2021-08-20 22:16:38 +00:00
2021-09-03 02:57:34 +00:00
def get_tts_object(self, language: Language) -> dict[str, any]:
2021-09-02 01:11:31 +00:00
carddb = CardDB()
# unique face urls used
unique_faces = set([
card[language].face
for card in self
])
# lookup for indices of urls
2021-09-02 01:11:31 +00:00
face_indices = {
url: i + 1
for i, url in enumerate(unique_faces)
}
2021-08-18 15:38:58 +00:00
# build the "CustomDeck" dictionary
2021-08-16 23:35:57 +00:00
custom_deck = {
2021-08-18 15:38:58 +00:00
str(i): {
2021-08-16 23:35:57 +00:00
"NumWidth": "10",
"NumHeight": "7",
2021-09-02 01:11:31 +00:00
"FaceURL": carddb.get_face_url(face),
2021-08-18 11:49:34 +00:00
"BackURL": CARD_BACK_URL,
2021-09-02 01:11:31 +00:00
} for face, i in face_indices.items()
2021-08-16 23:35:57 +00:00
}
2021-08-18 15:38:58 +00:00
# values both in main deck and each contained card
2021-08-16 23:35:57 +00:00
common_dict = {
"Transform": {
"scaleX": 2.17822933,
"scaleY": 1.0,
2021-08-23 20:03:13 +00:00
"scaleZ": 2.17822933,
"rotY": 180.0,
2021-08-16 23:35:57 +00:00
},
"Locked": False,
"Grid": True,
"Snap": True,
"Autoraise": True,
"Sticky": True,
"Tooltip": True,
"GridProjection": False,
}
2021-08-18 15:38:58 +00:00
# cards contained in deck
2021-08-16 23:35:57 +00:00
contained_objects = [
{
"Nickname": card[language].name,
"Description": card[language].text,
2021-09-02 01:11:31 +00:00
"CardID": 100 * face_indices[card[language].face] + card.index,
2021-08-16 23:35:57 +00:00
2021-08-18 15:38:58 +00:00
"Name": "Card",
2021-08-16 23:35:57 +00:00
"Hands": True,
"SidewaysCard": False,
2021-08-18 14:52:32 +00:00
} | common_dict for card in self
2021-08-16 23:35:57 +00:00
]
2021-08-18 15:38:58 +00:00
# extract the card ids
2021-08-16 23:35:57 +00:00
deck_ids = [
contained_object["CardID"]
for contained_object in contained_objects
]
2021-08-18 15:38:58 +00:00
# create the deck dictionary
2021-09-03 00:46:04 +00:00
deck_dict = {"ObjectStates": [
2021-08-16 23:35:57 +00:00
{
2021-08-18 14:52:32 +00:00
"Nickname": self.name,
2021-08-18 11:49:34 +00:00
"Description": self.__description,
2021-08-16 23:35:57 +00:00
"DeckIDs": deck_ids,
"CustomDeck": custom_deck,
"ContainedObjects": contained_objects,
2021-08-18 15:38:58 +00:00
"Name": "Deck",
"Hands": False,
"SidewaysCard": False,
2021-08-16 23:35:57 +00:00
} | common_dict
]}
2021-09-03 00:46:04 +00:00
if self.__face_down:
# flip the deck
deck_dict["ObjectStates"][0]["Transform"]["rotZ"] = 180.0
return deck_dict
2021-09-03 02:57:34 +00:00
def get_json(self, language: Language) -> str:
return json.dumps(self.get_tts_object(language), indent=2)
def save(self, language: Language) -> None:
2021-08-18 15:38:58 +00:00
# only save if the deck contains cards
if self:
2021-08-23 14:00:17 +00:00
if not os.path.exists(DECKS_DIR_NAME):
os.mkdir(DECKS_DIR_NAME)
2021-09-03 02:57:34 +00:00
with open(os.path.join(DECKS_DIR_NAME, self.file_name), "w") as file:
file.write(self.get_json(language))