async def down_ex(self, session, source, region, target, extract): dl_target = os.path.join(self.dl_dir, region, target) check_target_path(dl_target) async with session.get(source) as resp: assert resp.status == 200 if self.stdout_log: print(f'Download {dl_target} from {source}') try: with open(dl_target, 'wb') as f: f.write(await resp.read()) except: with open(os.path.join(dl_target, os.path.basename(dl_target)), 'wb') as f: f.write(await resp.read()) _, ext = os.path.splitext(dl_target) if len(ext) > 0: if self.stdout_log: print('Skipped', dl_target) return None if extract is None: extract = os.path.dirname(target).replace('/', '_') ex_target = os.path.join(region, extract) am = AssetsManager(dl_target) texture_2d = {} for asset in am.assets.values(): for obj in asset.objects.values(): result = unpack(obj, ex_target, self.ex_dir, self.ex_img_dir, stdout_log=self.stdout_log) if result and result[1]: texture_2d[result[0]] = result[1] if len(texture_2d) > 0: return texture_2d
def extract_assets(src): # load source am = AssetsManager(src) # iterate over assets for asset in am.assets.values(): # assets without container / internal path will be ignored for now if not asset.container: continue # check which mode we will have to use num_cont = sum(1 for obj in asset.container.values() if obj.type in TYPES) num_objs = sum(1 for obj in asset.objects.values() if obj.type in TYPES) # check if container contains all important assets, if yes, just ignore the container if num_objs <= num_cont * 2: for asset_path, obj in asset.container.items(): fp = os.path.join(DST, *asset_path.split('/')[IGNOR_DIR_COUNT:]) export_obj(obj, fp) # otherwise use the container to generate a path for the normal objects else: extracted = [] # find the most common path occurence_count = Counter(os.path.splitext(asset_path)[0] for asset_path in asset.container.keys()) local_path = os.path.join(DST, *occurence_count.most_common(1)[0][0].split('/')[IGNOR_DIR_COUNT:]) for obj in asset.objects.values(): if obj.path_id not in extracted: extracted.extend(export_obj(obj, local_path, append_name=True))
def mp_download_extract(target, source_list, extract, region, dl_dir, overwrite, ex_dir, ex_img_dir, stdout_log): base_dl_target = os.path.join(dl_dir, region, target) check_target_path(base_dl_target) downloaded = [] for idx, source in enumerate(source_list): if len(source_list) > 1: dl_target = base_dl_target + str(idx) else: dl_target = base_dl_target if overwrite or not os.path.exists(dl_target): if stdout_log: print(f'Download {dl_target} from {source}', flush=True) try: urllib.request.urlretrieve(source, dl_target) except Exception as e: print(str(e)) continue downloaded.append(dl_target) print('.', end='', flush=True) # return target, extract, region, downloaded # def mp_extract(target, extract, downloaded, region, ex_dir, ex_img_dir, stdout_log): if extract is None: extract = os.path.dirname(target).replace('/', '_') ex_target = os.path.join(region, extract) texture_2d = {} for dl_target in downloaded: am = AssetsManager(dl_target) for asset in am.assets.values(): for obj in asset.objects.values(): unpack(obj, ex_target, ex_dir, ex_img_dir, texture_2d, stdout_log=stdout_log) print('-', end='', flush=True) return texture_2d
def unpack_asset(file_path, destination_folder, root=None, source_folder=None): # load that file via AssetsManager am = AssetsManager(file_path) # iterate over all assets and named objects for asset in am.assets.values(): for obj in asset.objects.values(): # only process specific object types # print(obj.type, obj.container) obj_type_str = str(obj.type) if obj_type_str in unpack_dict: # parse the object data data = obj.read() # create destination path if root and source_folder: intermediate = root.replace(source_folder, '') else: intermediate = '' if obj_type_str == 'GameObject': dest = os.path.join(destination_folder, intermediate) unpack_dict[obj_type_str](data, dest) elif data.name: dest = os.path.join(destination_folder, intermediate, data.name) unpack_dict[obj_type_str](data, dest)
def load_mesh(filepath, require_name=None): am = AssetsManager(filepath) for obj in am.objects: if obj.type == "Mesh": objdata = obj.read() if require_name and require_name != objdata.name: continue data = objdata.export().splitlines() return data
def extract_target(self, dl_target, ex_target, texture_2d): am = AssetsManager(dl_target) for asset in am.assets.values(): for obj in asset.objects.values(): unpack(obj, ex_target, self.ex_dir, self.ex_img_dir, texture_2d, stdout_log=self.stdout_log)
async def down_ex(self, session, source, region, target, extract): dl_target = os.path.join(self.dl_dir, region, target) check_target_path(dl_target) async with session.get(source) as resp: assert resp.status == 200 if self.stdout_log: print(f'Download {dl_target}, {source}') with open(dl_target, 'wb') as f: f.write(await resp.read()) ex_target = os.path.join(self.ex_dir, region, extract) am = AssetsManager(dl_target) for asset in am.assets.values(): for obj in asset.objects.values(): unpack(obj, ex_target, self.stdout_log)
def _do(src): global g_containers am = AssetsManager(src) for asset in am.assets.values(): for asset_path, obj in asset.container.items(): contain(obj, asset_path) if not obj.path_id: af = obj.assets_file for o in af.objects.values(): #name = o.read().name name = o.read().name.split('/')[-1] if name: path = asset_path + '/' + name else: path = asset_path + '/' + '_' export_obj(o, path) continue export_obj(obj, asset_path)
def read_orig_file(src): global g_containers global queue, extracted am = AssetsManager(src) queue = {} extracted = {} for asset in am.assets.values(): for o in asset.objects.values(): dprint(o, o.read().name, o.path_id) queue[o.path_id] = o for asset in am.assets.values(): for asset_path, obj in asset.container.items(): if obj.path_id: export_obj(obj, asset_path, dup=True) else: print('obj no path_id') raise if ALLID: for _id, obj in queue.items(): if obj and _id not in extracted: export_obj(obj, '__/' + str(_id), noext=True)
def extractAssets(sourcePath: str, targetPath: str): for root, directories, files in os.walk(sourcePath): for filename in files: filePath = os.path.join(root, filename) print("Reading " + filePath + "...") try: manager = AssetsManager(filePath) for asset in manager.assets.values(): for obj in asset.objects.values(): ## Extract texture if obj.type in ["Texture2D", "Sprite"]: outputPath = root.replace(sourcePath, targetPath) if not os.path.exists(outputPath): os.makedirs(outputPath) data = obj.read() outputPath = os.path.join(outputPath, data.name) outputPath, extension = os.path.splitext( outputPath) outputPath = outputPath + ".png" if path.exists(outputPath): continue print(" Saving " + outputPath + "...") image = data.image image.save(outputPath) continue ##---------------------------------------------------------------------------------------- ## Extract text if obj.type in ["TextAsset"]: outputPath = root.replace(sourcePath, targetPath) if not os.path.exists(outputPath): os.makedirs(outputPath) data = obj.read() outputPath = os.path.join(outputPath, data.name) outputPath, extension = os.path.splitext( outputPath) outputPath = outputPath + ".txt" if path.exists(outputPath): continue print(" Saving " + outputPath + "...") with open(outputPath, "wb") as file: file.write(data.script) continue ##---------------------------------------------------------------------------------------- if obj.type in ["AudioClip"]: filePath = root.replace(sourcePath, targetPath) if not os.path.exists(filePath): os.makedirs(filePath) data = obj.read() for key in data.samples: outputPath = os.path.join(filePath, key) outputPath, extension = os.path.splitext( outputPath) outputPath = outputPath + ".wav" if path.exists(outputPath): continue print(" Saving " + outputPath + "...") sampleData = data.samples[key] with open(outputPath, "wb") as file: file.write(sampleData) ##---------------------------------------------------------------------------------------- ## Any other format are not support yet print(" ### Asset type '" + str(obj.type) + "' not support yet...") except KeyboardInterrupt: sys.exit() except struct.error as err: print("### " + str(err)) except: print("### Unknown error...")
def load_images(filepath: str): am = AssetsManager(filepath) for obj in am.objects: if obj.type == "Texture2D": yield obj.read()
def generateCards(self, imagePath, gwentPath): MAX_CARD_STRENGTH = 99 MAX_CARD_PROVISIONS = 99 MAX_CARD_ARMOR = 99 # Save chosen paths to a file with open('savedPaths.txt', 'w') as pathFile: pathFile.write(gwentPath + '\n') pathFile.write(imagePath + '\n') # Select all or certain cards if self.allImages.get() and self.numberofFiles: cardsToGenerate = self.cardData else: cardsToGenerate = [] for card in self.cardView.selection(): cardsToGenerate.append(self.cardView.set(card, column='ID')) numberOfCards = len(cardsToGenerate) cardsCompleted = 0 # Raise and error if gwent path, save path, or json file are not valid and if no cards were slected if not gwentPath or not ( gwentPath.endswith("GWENT The Witcher Card Game") or gwentPath.endswith("Gwent")): messagebox.showerror( "No Gwent Path", "Path to Gwent installation was invalid or not specified.") return if not imagePath: messagebox.showerror("No Image Path", "No path to save images to was specified.") return if not self.numberofFiles: messagebox.showerror("No JSON Data", "No JSON card data file was selected.") return if not numberOfCards and not self.allImages.get(): messagebox.showerror("No Card Selected", "No cards were selected.") return # Check to see if you have 4K graphics installed if (self.imageQuality.get() == "Uber (4K)") and not isfile("".join([ gwentPath, "/Gwent_Data/StreamingAssets/bundledassets/cardassets/textures/standard/uber/10000000" ])): messagebox.showerror( "Uber Graphics Not Installed", "You do not have the 4K graphics for Gwent installed.") return # Launch progress bar window progressWindow = tk.Toplevel() progressWindow.title("Generating...") jsonFrame = ttk.Frame(progressWindow) # Add a label to show how many cards have been completed progressString = tk.StringVar() progressString.set(" ".join( [str(cardsCompleted), "of", str(numberOfCards), "completed"])) progressLabel = ttk.Label(jsonFrame, textvariable=progressString) progressLabel.pack(padx='10', pady='5', side='top') # Add a progress bar progressBar = ttk.Progressbar(jsonFrame) progressBar.config(orient='horizontal', maximum=numberOfCards, length=250, mode='determinate') progressBar.pack(padx='10', pady='5', side='top') # Add a cancel button to quit early running = tk.BooleanVar() running.set(True) cancelButton = ttk.Button(jsonFrame, text='Cancel', command=lambda: running.set(False)) cancelButton.pack(pady='5', side='top') jsonFrame.config(height='250', width='200') jsonFrame.pack(side='top') progressWindow.config(height='250', width='200') progressWindow.iconbitmap('assets/favicon.ico') progressWindow.resizable(False, False) progressWindow.update() # Set the dimensions of the final cards based on quality dimensions = (992, 1424) quality = "uber" if (self.imageQuality.get() == "High"): dimensions = (497, 713) quality = "high" elif (self.imageQuality.get() == "Medium"): dimensions = (249, 357) quality = "medium" elif (self.imageQuality.get() == "Low"): dimensions = (125, 179) quality = "low" for card in cardsToGenerate: # Exit if cancel was pressed if not running.get(): break # if the card is valid and not a leader if self.cardData[card]['type'] != 'Leader' and self.cardData[card][ 'type'] is not None and self.cardData[card]['name'][ 'en-US'] is not None: # If the image is low quality, then export and crop it as a medium instead # because the low resolution card arts are stored differently in the game files the higher qualities if self.imageQuality.get() == "Low": dimensions = (249, 357) quality = "medium" # Export and crop the card art am = AssetsManager("".join([ gwentPath, "/Gwent_Data/StreamingAssets/bundledassets/cardassets/textures/standard/", quality, "/", self.cardData[card]['ingameArtId'], "0000" ])) for asset in am.assets.values(): for obj in asset.objects.values(): if obj.type == "Texture2D": data = obj.read() img = data.image newImg = img.crop((0, 0, dimensions[0], dimensions[1])) # Reset the quality specifics back to low if it is low and was exported as a medium if self.imageQuality.get() == "Low": dimensions = (125, 179) quality = "low" newImg = newImg.resize(dimensions) # Add gold or bronze border based on type (border tier not card type) if self.addBorders.get(): asset = Image.open("".join( ["assets/", self.cardData[card]['type'], ".png"])) if (quality != "uber"): asset = asset.resize(dimensions) newImg = Image.alpha_composite(newImg, asset) # Retrieve card type cardType = self.cardData[card]['cardType'] # If the optons said to add strength or type icons if self.addStrengthIcons.get(): # Get icon diamond based on faction diamond = Image.open("".join([ "assets/", self.cardData[card]['faction'], "_diamond.png" ])) # Get rarity icon based on rarity rarity = Image.open("".join( ["assets/", self.cardData[card]['rarity'], ".png"])) # Combine the two together strengthIcons = Image.alpha_composite(diamond, rarity) # If the card is a unit add strength and potentially armor if cardType == 'Unit': # Check strength and add the corresponding number to the card cardStrength = self.cardData[card]['strength'] if cardStrength > MAX_CARD_STRENGTH: cardStrength = MAX_CARD_STRENGTH strengthIcons = GwentCardExporter.placeNumber( self, cardStrength, "strength", strengthIcons) # Check if the card has armor and if so add the corresponding symbol and number cardArmor = self.cardData[card]['armor'] if cardArmor > MAX_CARD_ARMOR: cardArmor = MAX_CARD_ARMOR if cardArmor > 0: armor = Image.open("assets/Armor.png") strengthIcons = Image.alpha_composite( strengthIcons, armor) strengthIcons = GwentCardExporter.placeNumber( self, cardArmor, "armor", strengthIcons) # If the card is a strategem add the banner icon elif cardType == 'Strategem': strategem = Image.open("assets/Strategem.png") strengthIcons = Image.alpha_composite( strengthIcons, strategem) # If the card is a special add the flame icon elif cardType == 'Spell': special = Image.open("assets/Special.png") strengthIcons = Image.alpha_composite( strengthIcons, special) # If the card is an artifact add the goblet icon elif cardType == 'Artifact': artifact = Image.open("assets/Artifact.png") strengthIcons = Image.alpha_composite( strengthIcons, artifact) # Downsize if not generating 4K qualty if (quality != "uber"): strengthIcons = strengthIcons.resize(dimensions) # Add the final composite to the image newImg = Image.alpha_composite(newImg, strengthIcons) # If not a strategem and we are adding provisons if self.addProvisions.get() and not cardType == 'Strategem': # Get provisons icon provisionIcon = Image.open("assets/Provisions.png") # Get provisions square background based on the faction provisionSquare = Image.open("".join([ "assets/", self.cardData[card]['faction'], "_prov.png" ])) # Combine the two together provisions = Image.alpha_composite(provisionIcon, provisionSquare) # Check the provisions number and add the corresponding number cardProvisions = self.cardData[card]['provision'] if cardProvisions > MAX_CARD_PROVISIONS: cardProvisions == MAX_CARD_ARMOR provisions = GwentCardExporter.placeNumber( self, cardProvisions, "provisions", provisions) # Downsize if not generating in 4K quality if (quality != "uber"): provisions = provisions.resize(dimensions) # Add the final composite to the image newImg = Image.alpha_composite(newImg, provisions) # Save the card using the card's name and id number newImg.save("".join([ imagePath, "/", self.cardData[card]['name']['en-US'].replace(':', ''), "_", self.cardData[card]['ingameId'], "_", quality, ".png" ])) # Update progress label and progress bar cardsCompleted += 1 progressString.set(" ".join( [str(cardsCompleted), "of", str(numberOfCards), "completed"])) progressBar.step(1) progressWindow.update() progressWindow.destroy()
def extract_assets(src): global DST # load source am = AssetsManager(src) # iterate over assets for asset in am.assets.values(): # assets without container / internal path will be ignored for now if not asset.container: continue else: contain(asset.container) # check which mode we will have to use if TYPE_FILTER: num_cont = sum( 1 for obj in asset.container.values() if obj.type in TYPE_FILTER) num_objs = sum( 1 for obj in asset.objects.values() if obj.type in TYPE_FILTER) else: num_cont = sum( 1 for obj in asset.container.values() ) num_objs = sum( 1 for obj in asset.objects.values() ) # check if container contains all important assets, if yes, just ignore the container if num_objs <= num_cont * 2: for asset_path, obj in asset.container.items(): fp = os.path.join(DST, *asset_path.split('/')[IGNOR_DIR_COUNT:]) export_obj(obj, fp) # otherwise use the container to generate a path for the normal objects else: extracted = [] # find the most common path occurence_count = Counter(os.path.splitext(asset_path)[0] for asset_path in asset.container.keys()) for i in asset.container.keys(): # if 'master' in i : # print(occurence_count) # exit() local_path = os.path.join(DST, *occurence_count.most_common(1)[0][0].split('/')[IGNOR_DIR_COUNT:]) for obj in asset.objects.values(): if obj.path_id not in extracted: extracted.extend(export_obj(obj, local_path, append_name=True)) def filter(path, otype): global TYPE_FILTER global PATH_FILTER pick = 0 if PATH_FILTER: for i in PATH_FILTER: if i in path: pick = 1 else: pick = 1 if TYPE_FILTER and otype not in TYPE_FILTER: pick *= 0 return pick def export_obj(obj, fp: str, append_name: bool = False) -> list: if not filter(fp, obj.type): return [] #if obj.type in ['Material', 'Shader']: # bugged #if obj.type in ['MeshFilter', 'Mesh', 'Material']: # bugged #return [] data = obj.read() if data.name : slash = data.name.rfind('/') if slash != -1: aname = data.name[slash+1:] else: aname = data.name if aname == '': aname = '_' else : aname = '_' if append_name: bname = aname.encode('utf8') if len(bname) > 200: aname = aname[:50] fp = os.path.join(fp, aname) #dprint('aname', aname) #dprint('fp', fp) #dprint(str(obj.type)+':'+fp) fp, extension = os.path.splitext(fp) os.makedirs(os.path.dirname(fp), exist_ok=True) if 0 : pass elif obj.type == 'MonoScript': return monoscript(data, obj, fp, extension) elif obj.type == 'MonoBehaviour': return monobehaviour(data, obj, fp, extension) elif obj.type == 'TextAsset': return textasset(data, obj, fp, extension) elif obj.type == "Sprite": return sprite(data, obj, fp, extension) elif obj.type == "Texture2D": return texture2d(data, obj, fp, extension) elif obj.type == "GameObject": return gameobject(data, obj, fp, extension) else: return common(data, obj, fp, extension) return [obj.path_id] def common(data, obj, fp, extension): return [] f = open(f"{fp}.txt", 'w') #fb = open(f"{fp}.bin", 'wb') f.write(data.dump()) #fb.write(data.get_raw_data()) return [obj.path_id] def gameobject(data, obj, fp, extension): fp += '.go.txt' with open(f"{fp}", 'a') as f: f.write('%s\n++++++++++++++++++++\n'%obj.path_id) go = obj.read() cs = go.components for i in cs: data = i.read() f.write('%s\n--------------------\n'%data.path_id) f.write(data.dump().replace('\r','')) f.write('\n') f.close() return [obj.path_id] def monobehaviour(data, obj, fp, extension): if not extension: extension = '.txt' if data.name == '': return [] with open(f"{fp}{extension}", 'a') as f: f.write(str(obj.path_id)) f.write('\n+++++++++++++++\n') f.write(data.dump().replace('\r','')) return [obj.path_id] def monoscript(data, obj, fp, extension): if not extension: extension = '.txt' with open(f"{fp}{extension}", 'w') as f: f.write(str(obj.path_id)) f.write('\n+++++++++++++++\n') f.write(data.dump().replace('\r','')) return [obj.path_id] def textasset(data, obj, fp, extension): if not extension: extension = '.txt' with open(f"{fp}{extension}", 'wb') as f: f.write(data.script) return [obj.path_id] def sprite(data, obj, fp, extension): extension = ".png" data.image.save(f"{fp}{extension}") return [obj.path_id, data.m_RD.texture.path_id, getattr(data.m_RD.alphaTexture, 'path_id', None)] def texture2d(data, obj, fp, extension): extension = ".png" fp = f"{fp}{extension}" if not os.path.exists(fp): try: data.image.save(fp) except EOFError: pass return [obj.path_id] if __name__ == '__main__': main()
def generateCards(self, imagePath, gwentPath): # Maximum values so a correct file is always chosen MAX_CARD_STRENGTH = 13 MAX_CARD_ARMOR = 10 MAX_CARD_PROVISIONS = 14 # Save chosen paths to a file with open('savedPaths.txt', 'w') as pathFile: pathFile.write(gwentPath + '\n') pathFile.write(imagePath + '\n') # Select all or certain cards if self.allImages.get() and self.numberofFiles: cardsToGenerate = self.cardData else: cardsToGenerate = [] for card in self.cardView.selection(): cardsToGenerate.append(self.cardView.set(card, column='ID')) numberOfCards = len(cardsToGenerate) cardsCompleted = 0 # Raise and error if gwent path, save path, or json file are not valid and if no cards were slected if not gwentPath or not (gwentPath.endswith("GWENT The Witcher Card Game") or gwentPath.endswith("Gwent")): messagebox.showerror("No Gwent Path", "Path to Gwent installation was invalid or not specified.") return if not imagePath: messagebox.showerror("No Image Path", "No path to save images to was specified.") return if not self.numberofFiles: messagebox.showerror("No JSON Data", "No JSON card data file was selected.") return if not numberOfCards and not self.allImages.get(): messagebox.showerror("No Card Selected", "No cards were selected.") return # Launch progress bar window progressWindow = tk.Toplevel() progressWindow.title("Generating...") jsonFrame = ttk.Frame(progressWindow) # Add a label to show how many cards have been completed progressString = tk.StringVar() progressString.set(" ".join([str(cardsCompleted), "of", str(numberOfCards), "completed"])) progressLabel = ttk.Label(jsonFrame, textvariable = progressString) progressLabel.pack(padx='10', pady='5', side='top') # Add a progress bar progressBar = ttk.Progressbar(jsonFrame) progressBar.config(orient='horizontal', maximum=numberOfCards, length=250, mode='determinate') progressBar.pack(padx='10', pady='5', side='top') # Add a cancel button to quit early running = tk.BooleanVar() running.set(True) cancelButton = ttk.Button(jsonFrame, text='Cancel', command = lambda: running.set(False)) cancelButton.pack(pady='5', side='top') jsonFrame.config(height='250', width='200') jsonFrame.pack(side='top') progressWindow.config(height='250', width='200') progressWindow.iconbitmap('assets/favicon.ico') progressWindow.resizable(False, False) progressWindow.update() for card in cardsToGenerate: # Exit if cancel was pressed if not running.get(): break # if the card is valid and not a leader if self.cardData[card]['type'] != 'Leader' and self.cardData[card]['type'] is not None and self.cardData[card]['name']['en-US'] is not None: # Export and crop the card art am = AssetsManager("".join([gwentPath, "/Gwent_Data/StreamingAssets/bundledassets/cardassets/textures/standard/high/", self.cardData[card]['ingameArtId'], "0000"])) for asset in am.assets.values(): for obj in asset.objects.values(): if obj.type == "Texture2D": data = obj.read() img = data.image newImg = img.crop((0,0,496,712)) # Add gold or bronze border based on type (border tier not card type) if self.addBorders.get(): asset = Image.open("".join(["assets/", self.cardData[card]['type'], ".png"])) newImg = Image.alpha_composite(newImg, asset) # Retrieve card type cardType = self.cardData[card]['cardType'] # If the optons said to add strength or type icons if self.addStrengthIcons.get(): # Add icon diamond based on faction asset = Image.open("".join(["assets/", self.cardData[card]['faction'], "_diamond.png"])) newImg = Image.alpha_composite(newImg, asset) # Add rarity icon based on rarity asset = Image.open("".join(["assets/", self.cardData[card]['rarity'], ".png"])) newImg = Image.alpha_composite(newImg, asset) # If the card is a strategem add the banner icon (no provisions needed) if cardType == 'Strategem': asset = Image.open("assets/Strategem.png") newImg = Image.alpha_composite(newImg, asset) # If the card is a unit add strength and potentially armor elif cardType == 'Unit': # Check strength and add the corresponding number to the card cardStrength = self.cardData[card]['strength'] if cardStrength > MAX_CARD_STRENGTH: cardStrength = 0 asset = Image.open("".join(["assets/s_", str(cardStrength), ".png"])) newImg = Image.alpha_composite(newImg, asset) # Check if the card has armor and if so add the corresponding symbol and number cardArmor = self.cardData[card]['armor'] if cardArmor <= MAX_CARD_ARMOR and cardArmor > 0: asset = Image.open("assets/armor.png") newImg = Image.alpha_composite(newImg, asset) asset = Image.open("".join(["assets/a_", str(cardArmor), ".png"])) newImg = Image.alpha_composite(newImg, asset) # If the card is a special add the flame icon elif cardType == 'Spell': # place flame icon asset = Image.open("assets/Special.png") newImg = Image.alpha_composite(newImg, asset) # If the card is an artifact add the goblet icon elif cardType == 'Artifact': # place goblet icon asset = Image.open("assets/Artifact.png") newImg = Image.alpha_composite(newImg, asset) # If not a strategem and we are adding provisons if self.addProvisions.get() and not cardType == 'Strategem': # Add provisons icon asset = Image.open("assets/provisions.png") newImg = Image.alpha_composite(newImg, asset) # Add provisions square background based on the faction asset = Image.open("".join(["assets/", self.cardData[card]['faction'], "_prov.png"])) newImg = Image.alpha_composite(newImg, asset) # Check the provisions number and add the corresponding number cardProvisions = self.cardData[card]['provision'] if cardProvisions > MAX_CARD_PROVISIONS: cardProvisions == 0 asset = Image.open("".join(["assets/p_", str(cardProvisions), ".png"])) newImg = Image.alpha_composite(newImg, asset) # Save the card using the card's name and id number newImg.save("".join([imagePath, "/", self.cardData[card]['name']['en-US'].replace(':', ''), "_", self.cardData[card]['ingameId'], ".png"])) # Update progress label and progress bar cardsCompleted += 1 progressString.set(" ".join([str(cardsCompleted), "of", str(numberOfCards), "completed"])) progressBar.step(1) progressWindow.update() progressWindow.destroy()