From 921ea31a4ed1a18c9854366787fa65783ae12644 Mon Sep 17 00:00:00 2001 From: DazedAnon Date: Thu, 12 Sep 2024 16:58:00 -0500 Subject: [PATCH] Changes to wolf and images --- modules/images.py | 8 +- modules/wolf.py | 295 +++++++++++++++++++++++++--------------------- vocab.txt | 237 +++++++++++++++++++++++++++++++++++++ 3 files changed, 403 insertions(+), 137 deletions(-) diff --git a/modules/images.py b/modules/images.py index 0adb0f5..8007df2 100644 --- a/modules/images.py +++ b/modules/images.py @@ -70,9 +70,9 @@ def handleImages(folderName, estimate): originalList = translatedData[0][1] dimensionsList = translatedData[0][2] image = stringToImage(translatedList[i], dimensionsList[i][0], dimensionsList[i][1]) - image.save(rf'translated/{folderName}/{originalList[i]}.png', quality=100) + image.save(rf'translated/{folderName}/{translatedList[i]}.png', quality=100) except Exception as e: - PBAR.write(f'{originalList[i]}: {str(e)}') + PBAR.write(f'{translatedList[i]}: {str(e)}') #Ignore Error # Print File @@ -173,7 +173,7 @@ def stringToImage(text, width, height, font_path='fonts/TsunagiGothic.ttf', scal y = (scaled_height - text_height) // 2 # Draw the text on the image - draw.text((x, y), text, font=font, fill=(0, 0, 0, 255)) + draw.text((x, y), text, font=font, fill=(255, 255, 255, 255)) # Resize back to the original dimensions to get a clearer text rendering image = image.resize((width, height), Image.LANCZOS,) @@ -192,7 +192,7 @@ def getImageDimensions(file_path): def processImagesDir(directory_path, imageList): for file_name in os.listdir(directory_path): # .png and Japanese - if '.png' in file_name and re.search(r'[一-龠ぁ-ゔァ-ヴー]+', file_name): + if '.png' in file_name and re.search(r'[一-龠ぁ-ゔァ-ヴー]+', file_name) and file_name.replace('.png', '') in VOCAB and len(file_name) > 5: file_path = os.path.join(directory_path, file_name) if os.path.isfile(file_path): # Check if the file is an image diff --git a/modules/wolf.py b/modules/wolf.py index 1a35f28..0575a3a 100644 --- a/modules/wolf.py +++ b/modules/wolf.py @@ -35,6 +35,7 @@ BRFLAG = False # If the game uses
instead FIXTEXTWRAP = True # Overwrites textwrap IGNORETLTEXT = False # Ignores all translated text. MISMATCH = [] # Lists files that throw a mismatch error (Length of GPT list response is wrong) +FILENAME = None BRACKETNAMES = False # Pricing - Depends on the model https://openai.com/pricing @@ -48,7 +49,7 @@ if 'gpt-3.5' in MODEL: elif 'gpt-4' in MODEL: INPUTAPICOST = .005 OUTPUTAPICOST = .015 - BATCHSIZE = 20 + BATCHSIZE = 40 FREQUENCY_PENALTY = 0.1 #tqdm Globals @@ -64,9 +65,9 @@ CODE102 = False CODE122 = False # Other -CODE210 = True -CODE300 = True -CODE250 = False +CODE210 = False +CODE300 = False +CODE250 = True # Database NPCFLAG = False @@ -78,8 +79,9 @@ ENEMYFLAG = False WEAPONFLAG = False def handleWOLF(filename, estimate): - global ESTIMATE, TOKENS + global ESTIMATE, TOKENS, FILENAME ESTIMATE = estimate + FILENAME = filename # Translate start = time.time() @@ -365,7 +367,7 @@ def searchCodes(events, pbar, jobList, filename): # # Validate and Set Data # codeList[i]['stringArgs'][1] = translatedText if 'stringArgs' in codeList[i] and len(codeList[i]['stringArgs']) > 1: - imageRegex = r'(\\?r?\\?n?_\w+\r\n)|(@-?\d?)(\d?-?\d?[^\r]+?)(\r\n|$)|(_PDC)|(>\r\n)|(^[#])|(\r\n@$)|(/)|(_SS_)|(\r\n[@/]-?\d?\r\n)' + imageRegex = r'(\r?\n?_\w+\r?\n?)|(@-?\d?\r\n)|(@-?\d?[^\r])(\d?-?\d?[^\r]+?)(\r\n|$)|(_PDC)|(>\r\n)|(^[#])|(\r\n@$)|(/)|(_SS_)|(\r\n[@/]-?\d?\r\n)' fontSize = 24 # Grab String @@ -383,9 +385,9 @@ def searchCodes(events, pbar, jobList, filename): j = 0 translatedText = '' while j < len(cleanedList): - if j > 0 and ('@' in cleanedList[j] or '/' in cleanedList[j]) and j < len(cleanedList)-1 and re.search(r'(\r\n[@/]-?\d?\r\n)', cleanedList[j]) is None: + if ('@' in cleanedList[j] or '/' in cleanedList[j]) and j < len(cleanedList)-1 and re.search(r'([@/]-?\d?\r\n)', cleanedList[j]) is None: # Setup @ - if '@' not in cleanedList[j-1] and '/' not in cleanedList[j-1] and '_' not in cleanedList[j-1]: + if j > 0 and '@' not in cleanedList[j-1] and '/' not in cleanedList[j-1] and '_' not in cleanedList[j-1]: cleanedList[j-1] = cleanedList[j-1] + cleanedList[j+1] else: cleanedList.insert(j, cleanedList[j+1]) @@ -406,8 +408,14 @@ def searchCodes(events, pbar, jobList, filename): # Pass 2 else: if all(x not in str for x in ['_', '@', '>', '/',]) and str != '\r\n': + # Decide Wrap + if codeList[i]['stringArgs'][0] == '[移]サウンドノベル': + width = 40 + else: + width = WIDTH + # Add Textwrap and Font - list300[0] = textwrap.fill(list300[0], WIDTH) + list300[0] = textwrap.fill(list300[0], width) list300[0] = list300[0].replace('\n', f'\r\n\\f[{fontSize}]') list300[0] = f'\\f[{fontSize}]{list300[0]}\r\n' translatedText += list300[0] @@ -419,6 +427,8 @@ def searchCodes(events, pbar, jobList, filename): if setData: # Formatting Fixes translatedText = translatedText.replace('*"', '* "') + translatedText = translatedText.replace('\r\n\r\n', '\r\n') + translatedText = re.sub(r'[^\S\r\n]+', ' ', translatedText) codeList[i]['stringArgs'][1] = translatedText @@ -483,11 +493,11 @@ def searchCodes(events, pbar, jobList, filename): codeList[i]['stringArgs'][0] = translatedText ### Event Code: 300 Common Events - if codeList[i]['code'] == 300 and CODE300 == True and len(codeList[i]['stringArgs']) > 1: + if codeList[i]['code'] == 122 and CODE300 == True and len(codeList[i]['stringArgs']) > 0: # Choices - if codeList[i]['stringArgs'][0] == "選択肢/確認": + if codeList[i]['stringArgs'][0] == "m_可変式選択肢": # Grab String - choiceList = codeList[i]['stringArgs'][1].split(',') + choiceList = codeList[i]['stringArgs'][1].split('\r\n') # Translate Question question = codeList[i]['stringArgs'][2] @@ -510,20 +520,28 @@ def searchCodes(events, pbar, jobList, filename): choiceListTL[j] = choiceListTL[j].replace(', ', '、') # Convert to String and Set - translatedText = ','.join(choiceListTL) + translatedText = '\r\n'.join(choiceListTL) codeList[i]['stringArgs'][1] = translatedText # Dialogue elif codeList[i]['stringArgs'][0] == "Hメッセージ" \ or codeList[i]['stringArgs'][0] == 'Hしらべる' \ + or codeList[i]['stringArgs'][0] == '[共]Hメッセージ+' \ + or codeList[i]['stringArgs'][0] == '[共]ポップアップ表示' \ + or codeList[i]['stringArgs'][0] == 'm_謎冒頭' \ + or (codeList[i]['codeStr'] == 'SetString' and '@' in codeList[i]['stringArgs'][0])\ or codeList[i]['stringArgs'][0] == '[移]サウンドノベル': - imageRegex = r'(\r?\n?_\w+\r?\n?)|(@-?\d?\r\n)|(@-?\d?[^\r])(\d?-?\d?[^\r]+?)(\r\n|$)|(_PDC)|(>\r\n)|(^[#])|(\r\n@$)|(/)|(_SS_)|(\r\n[@/]-?\d?\r\n)' + imageRegex = r'(\r?\n?_\w+\r?\n?)|(@-?\d?\r\n)|(@-?\d?[^\r*])(\d?-?\d?[^\r]+?)(\r\n|$)|(_PDC)|(>\r\n)|(^[#])|(\r\n@$)|(/)|(_SS_)|(\r\n[@/]-?\d?\r\n)' fontSize = 24 # Grab String - jaString = codeList[i]['stringArgs'][1] + if codeList[i]['codeStr'] != 'SetString': + jaString = codeList[i]['stringArgs'][1] + else: + jaString = codeList[i]['stringArgs'][0] jaString = jaString.replace('\u3000', ' ') jaString = jaString.replace('#', '') + jaString = re.sub(r'[^\r]\n', '\r\n', jaString) # Grab and Split jaStringList = re.split(imageRegex, jaString) @@ -560,12 +578,12 @@ def searchCodes(events, pbar, jobList, filename): if all(x not in str for x in ['_', '@', '>', '/',]) and str != '\r\n': # Decide Wrap if codeList[i]['stringArgs'][0] == '[移]サウンドノベル': - width = 50 + width = 40 else: width = WIDTH # Add Textwrap and Font - list300[0] = textwrap.fill(list300[0], WIDTH) + list300[0] = textwrap.fill(list300[0], width) list300[0] = list300[0].replace('\n', f'\r\n\\f[{fontSize}]') list300[0] = f'\\f[{fontSize}]{list300[0]}\r\n' translatedText += list300[0] @@ -577,44 +595,49 @@ def searchCodes(events, pbar, jobList, filename): if setData: # Formatting Fixes translatedText = translatedText.replace('*"', '* "') + translatedText = translatedText.replace('\r\n\r\n', '\r\n') translatedText = re.sub(r'[^\S\r\n]+', ' ', translatedText) - codeList[i]['stringArgs'][1] = translatedText + if codeList[i]['codeStr'] != 'SetString': + codeList[i]['stringArgs'][1] = translatedText + else: + codeList[i]['stringArgs'][0] = translatedText ### Event Code: 250 Common Events if codeList[i]['code'] == 250 and CODE250 == True: foundTerm = False # Validate size - if len(codeList[i]['stringArgs']) > 0: - # Grab String - jaString = codeList[i]['stringArgs'][0] + if len(codeList[i]['stringArgs']) > 2: + if codeList[i]['stringArgs'][1] == "┗所持防具個数" and codeList[i]['stringArgs'][2] != '': + # Grab String + jaString = codeList[i]['stringArgs'][2] - # Catch Vars that may break the TL - varString = '' - matchList = re.findall(r'^[\\_]+[\w]+\[[a-zA-Z0-9\\\[\]\_,\s-]+\]', jaString) - if len(matchList) != 0: - varString = matchList[0] - jaString = jaString.replace(matchList[0], '') + # Catch Vars that may break the TL + varString = '' + matchList = re.findall(r'^[\\_]+[\w]+\[[a-zA-Z0-9\\\[\]\_,\s-]+\]', jaString) + if len(matchList) != 0: + varString = matchList[0] + jaString = jaString.replace(matchList[0], '') - # Check if term already translated - for j in range(len(TERMSLIST)): - if jaString == TERMSLIST[j][0]: - translatedText = TERMSLIST[j][1] - foundTerm = True + # Check if term already translated + for j in range(len(TERMSLIST)): + if jaString == TERMSLIST[j][0]: + translatedText = TERMSLIST[j][1] + foundTerm = True - # Translate - if foundTerm == False: - response = translateGPT(jaString, f'Reply with the {LANGUAGE} translation of the text.', False) - translatedText = response[0] - totalTokens[0] = response[1][0] - totalTokens[1] = response[1][1] - TERMSLIST.append([jaString, translatedText]) + # Translate + if foundTerm == False: + response = translateGPT(jaString, f'Reply with the {LANGUAGE} translation of the text.', False) + translatedText = response[0] + totalTokens[0] = response[1][0] + totalTokens[1] = response[1][1] + TERMSLIST.append([jaString, translatedText]) - # Add back Potential Variables in String - translatedText = varString + translatedText + # Add back Potential Variables in String + translatedText = varString + translatedText - # Set Data - codeList[i]['stringArgs'][0] = translatedText + # Set Data + codeList[i]['stringArgs'][2] = translatedText ### Iterate i += 1 @@ -697,7 +720,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens = [0, 0] initialJAString = '' tableList = events - font = '\\f[18]' + font = '' global LOCK global NAMESLIST global MISMATCH @@ -726,7 +749,7 @@ def searchDB(events, pbar, jobList, filename): # Parse for j in range(len(dataList)): # Name - if '翔太' in dataList[j].get('name'): + if 'キャラ名' in dataList[j].get('name'): # Pass 1 (Grab Data) if setData == False: if dataList[j].get('value') != '': @@ -818,102 +841,105 @@ def searchDB(events, pbar, jobList, filename): scenarioList[2].pop(0) # Grab Items - if table['name'] == '道具' and ITEMFLAG == True: - for item in table['data']: - dataList = item['data'] + if table['name'] == '宿泊施設' and ITEMFLAG == True: + with open('translations.txt', 'a') as file: + for item in table['data']: + dataList = item['data'] - # Parse - for j in range(len(dataList)): - # Name - if '道具名' in dataList[j].get('name'): - # Pass 1 (Grab Data) - if setData == False: - if dataList[j].get('value') != '': - itemList[0].append(dataList[j].get('value')) + # Parse # + for j in range(len(dataList)): + # Name + if 'NULL' in dataList[j].get('name'): + # Pass 1 (Grab Data) + if setData == False: + if dataList[j].get('value') != '': + itemList[0].append(dataList[j].get('value')) - # Pass 2 (Set Data) - else: - if dataList[j].get('value') != '': - dataList[j].update({'value': itemList[0][0]}) - itemList[0].pop(0) - - # Description - if 'NULL' in dataList[j].get('name'): - # Pass 1 (Grab Data) - if setData == False: - if dataList[j].get('value') != '': - # Remove Textwrap - jaString = dataList[j].get('value') - jaString = jaString.replace('\n', ' ') - jaString = jaString.replace('\r', '') - jaString = re.sub(r'[\\]+f\[\d+\]', '', jaString) + # Pass 2 (Set Data) + else: + if dataList[j].get('value') != '': + file.write(f'{dataList[j].get('value')} ({itemList[0][0]})\n') + dataList[j].update({'value': itemList[0][0]}) + itemList[0].pop(0) + + # Description + if dataList[j].get('name') == '選2文字列(夜時非表示': + # Pass 1 (Grab Data) + if setData == False: + if dataList[j].get('value') != '': + # Remove Textwrap + jaString = dataList[j].get('value') + jaString = jaString.replace('\n', ' ') + jaString = jaString.replace('\r', '') + jaString = re.sub(r'[\\]+f\[\d+\]', '', jaString) - # Append Data - itemList[1].append(jaString) + # Append Data + itemList[1].append(jaString) - # Pass 2 (Set Data) - else: - if dataList[j].get('value') != '': - # Textwrap - translatedText = itemList[1][0] - translatedText = textwrap.fill(translatedText, LISTWIDTH) - translatedText = font + translatedText + # Pass 2 (Set Data) + else: + if dataList[j].get('value') != '': + # Textwrap + translatedText = itemList[1][0] + translatedText = textwrap.fill(translatedText, LISTWIDTH) + translatedText = translatedText.replace('\n', '\r\n') + translatedText = font + translatedText - # Set Data - dataList[j].update({'value': translatedText}) - itemList[1].pop(0) + # Set Data + dataList[j].update({'value': translatedText}) + itemList[1].pop(0) - # Description 2 - if '使用後文章[移動]' in dataList[j].get('name'): - # Pass 1 (Grab Data) - if setData == False: - if dataList[j].get('value') != '': - # Remove Textwrap - jaString = dataList[j].get('value') - jaString = jaString.replace('\n', ' ') - jaString = jaString.replace('\r', '') - jaString = re.sub(r'[\\]+f\[\d+\]', '', jaString) + # Description 2 + if dataList[j].get('name') == '選3文字列': + # Pass 1 (Grab Data) + if setData == False: + if dataList[j].get('value') != '': + # Remove Textwrap + jaString = dataList[j].get('value') + jaString = jaString.replace('\n', ' ') + jaString = jaString.replace('\r', '') + jaString = re.sub(r'[\\]+f\[\d+\]', '', jaString) - # Append Data - itemList[2].append(jaString) + # Append Data + itemList[2].append(jaString) - # Pass 2 (Set Data) - else: - if dataList[j].get('value') != '': - # Textwrap - translatedText = itemList[2][0] - translatedText = textwrap.fill(translatedText, LISTWIDTH) - translatedText = font + translatedText + # Pass 2 (Set Data) + else: + if dataList[j].get('value') != '': + # Textwrap + translatedText = itemList[2][0] + translatedText = textwrap.fill(translatedText, LISTWIDTH) + translatedText = font + translatedText - # Set Data - dataList[j].update({'value': translatedText}) - itemList[2].pop(0) + # Set Data + dataList[j].update({'value': translatedText}) + itemList[2].pop(0) - # Description 3 - if '使用時文章[戦]' in dataList[j].get('name'): - # Pass 1 (Grab Data) - if setData == False: - if dataList[j].get('value') != '': - # Remove Textwrap - jaString = dataList[j].get('value') - jaString = jaString.replace('\n', ' ') - jaString = jaString.replace('\r', '') - jaString = re.sub(r'[\\]+f\[\d+\]', '', jaString) + # Description 3 + if dataList[j].get('name') == '┗セ⑥_昼(になった)': + # Pass 1 (Grab Data) + if setData == False: + if dataList[j].get('value') != '': + # Remove Textwrap + jaString = dataList[j].get('value') + jaString = jaString.replace('\n', ' ') + jaString = jaString.replace('\r', '') + jaString = re.sub(r'[\\]+f\[\d+\]', '', jaString) - # Append Data - itemList[3].append(jaString) + # Append Data + itemList[3].append(jaString) - # Pass 2 (Set Data) - else: - if dataList[j].get('value') != '': - # Textwrap - translatedText = itemList[3][0] - translatedText = textwrap.fill(translatedText, LISTWIDTH) - translatedText = font + translatedText + # Pass 2 (Set Data) + else: + if dataList[j].get('value') != '': + # Textwrap + translatedText = itemList[3][0] + translatedText = textwrap.fill(translatedText, LISTWIDTH) + translatedText = font + translatedText - # Set Data - dataList[j].update({'value': translatedText}) - itemList[3].pop(0) + # Set Data + dataList[j].update({'value': translatedText}) + itemList[3].pop(0) # Grab Armors if table['name'] == '防具' and ARMORFLAG == True: @@ -1160,7 +1186,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT(NPCList[0], 'Reply with only the '+ LANGUAGE +' translation of the RPG item name', True) + response = translateGPT(NPCList[0], 'Reply with only the '+ LANGUAGE +' translation of the RPG enemy name', True) nameListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1229,7 +1255,7 @@ def searchDB(events, pbar, jobList, filename): translate = True # ITEMS - if len(itemList[0]) > 0: + if len(itemList[0]) > 0 or len(itemList[1]) > 0: # Progress Bar total = 0 for itemArray in itemList: @@ -1238,7 +1264,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT(itemList[0], 'Reply with only the '+ LANGUAGE +' translation of the RPG item name', True) + response = translateGPT(itemList[0], 'Reply with only the '+ LANGUAGE +' translation', True) nameListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1377,7 +1403,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT(collectionList[0], '', True) + response = translateGPT(collectionList[0], 'reply with only the gender neutral '+ LANGUAGE +' translation of the action log. Always start the sentence with Taro. For example, Translate \'Taroを倒した!\' as \'Taro was defeated!\'', True) nameListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1555,6 +1581,7 @@ def createContext(fullPromptFlag, subbedT): ハッサン (Hassan) - Male\n\ アロマ (Aroma) - Female\n\ ピッケ (Pikke) - Female\n\ +ドラオ (Dorao) - Male\n\ ' system = PROMPT + VOCAB if fullPromptFlag else \ @@ -1685,7 +1712,7 @@ def combineList(tlist, text): @retry(exceptions=Exception, tries=5, delay=5) def translateGPT(text, history, fullPromptFlag): - global PBAR + global PBAR, MISMATCH, FILENAME mismatch = False totalTokens = [0, 0] @@ -1754,6 +1781,8 @@ def translateGPT(text, history, fullPromptFlag): else: history = text[-10:] mismatch = False + if FILENAME not in MISMATCH: + MISMATCH.append(FILENAME) # Update Loading Bar with LOCK: diff --git a/vocab.txt b/vocab.txt index e2389b1..bc8e051 100644 --- a/vocab.txt +++ b/vocab.txt @@ -66,4 +66,241 @@ ME 音量 (ME Volume) ギャンデッド (Ganded) リーロランド (Liloland) ローバー (Roper) + +# Armors +アマカラ靴1 (Amakara Shoes 1) +お鍋のフタ (Pot Lid) +ライトシールド (Light Shield) +キトンシールド (Kiton Shield) +こうらの盾 (Shell Shield) +プラチナシールド (Platinum Shield) +魔法の盾 (Magic Shield) +シルバートレイ (Silver Tray) +皮の盾 (Leather Shield) +青銅の盾 (Bronze Shield) +ホワイトシールド (White Shield) +力の盾 (Power Shield) +水鏡の盾 (Water Mirror Shield) +ダークシールド (Dark Shield) +精霊の盾 (Spirit Shield) +スチヌラの盾 (Stinura Shield) +輪廻の盾 (Reincarnation Shield) +はぐれスチルの盾 (Stray Steel Shield) +破滅の盾 (Shield of Ruin) +鉄の盾 (Iron Shield) +鋼の盾 (Steel Shield) +氷の盾 (Ice Shield) +炎の盾 (Flame Shield) +玉鋼の盾 (Jewel Steel Shield) +ドラゴンシールド (Dragon Shield) +風神の盾 (Wind God Shield) +オーガシールド (Ogre Shield) +幻魔の盾 (Phantom Demon Shield) +女神の盾 (Goddess Shield) +シャハルの鏡 (Shahar's Mirror) +エンデの盾 (Ende's Shield) +スチルキングの盾 (Steel King Shield) +天空の盾 (Sky Shield) +ロトの盾 (Roto's Shield) +光の盾 (Light Shield) +皮の鎧 (Leather Armor) +くさりかたびら (Chain Mail) +鉄の胸当て (Iron Breastplate) +鋼の胸当て (Steel Breastplate) +プラチナメイル (Platinum Mail) +こうらの鎧 (Shell Armor) +ドラゴンスケイル (Dragon Scale) +シルバーメイル (Silver Mail) +ダンシングメイル (Dancing Mail) +魔法の鎧 (Magic Armor) +精霊の鎧 (Spirit Armor) +神秘の鎧 (Mystic Armor) +スチヌラ鎧 (Stenura Armor) +エンデの鎧 (Ende's Armor) +はぐれスチル鎧 (Stray Steel Armor) +勝利の鎧 (Victory Armor) +鉄の鎧 (Iron Armor) +鋼の鎧 (Steel Armor) +戦士の鎧 (Warrior's Armor) +ドラゴンメイル (Dragon Mail) +大地の鎧 (Earth Armor) +玉鋼の鎧 (Jewel Steel Armor) +氷の鎧 (Ice Armor) +炎の鎧 (Flame Armor) +魔神の鎧 (Demon Armor) +ミスリルアーマー (Mithril Armor) +ギガントアーマー (Gigant Armor) +幻魔の鎧 (Phantom Demon Armor) +女神の鎧 (Goddess Armor) +悪魔の鎧 (Devil Armor) +スチルキング鎧 (Steel King Armor) +布の服 (Cloth Garb) +旅人の服 (Traveler's Clothes) +貴族の服 (Noble's Clothes) +毛皮のコート (Fur Coat) +みかわしの服 (Evasion Clothes) +拳法着 (Martial Arts Wear) +かくれみの服 (Cloak of Invisibility) +竜の道着 (Dragon's Gi) +闇の衣 (Dark Robe) +レザーマント (Leather Mantle) +紅蓮のローブ (Crimson Robe) +やすらぎのローブ (Tranquil Robe) +魔法の法衣 (Magic Vestment) +神官のエプロン (Priest's Apron) +賢者のローブ (Sage's Robe) +天使のローブ (Angel's Robe) +不思議なボレロ (Mysterious Bolero) +精霊の法衣 (Spirit's Garb) +神秘のローブ (Mystic Robe) +ドラゴンローブ (Dragon Robe) +皮のドレス (Leather Dress) +絹のローブ (Silk Robe) +マジカルスカート (Magical Skirt) +シルクのビスチェ (Silk Bustier) +水の羽衣 (Water Robe) +光のドレス (Dress of Light) +プリンセスローブ (Princess Robe) +踊り子の服 (Dancer's Outfit) +バニースーツ (Bunny Suit) +あぶない水着 (Dangerous Swimsuit) +天使のレオタード (Angel's Leotard) +魔法のビキニ (Magic Bikini) +神秘のビスチェ (Mystic Bustier) +清き衣 (Pure Garment) +エッチな下着 (Sexy Underwear) +天空の鎧 (Sky Armor) +王者のマント (King's Mantle) +ロトの鎧 (Roto's Armor) +皮の帽子 (Leather Hat) +サークレット (Circlet) +毛皮のフード (Fur Hood) +神官の帽子 (Priest's Hat) +知識の帽子 (Hat of Knowledge) +ファントムマスク (Phantom Mask) +マジカルハット (Magical Hat) +般若の面 (Hannya Mask) +幸せの帽子 (Hat of Happiness) +不思議な帽子 (Mysterious Hat) +山彦の帽子 (Echo Hat) +うさみみバンド (Bunny Ears Band) +銀の髪飾り (Silver Hair Ornament) +ウィッチハット (Witch Hat) +黄金のティアラ (Golden Tiara) +スチールヘッドギア (Steel Headgear) +プラチナメット (Platinum Helmet) +サタンヘルム (Satan Helm) +武王のはちがね (War King's Headband) +ミスリルフード (Mithril Hood) +スチヌラヘルム (Stenura Helm) +不幸の兜 (Helmet of Misfortune) +はぐれスチルヘルム (Stray Steel Helm) +慈愛の兜 (Helmet of Compassion) +チェインフード (Chain Hood) +鉄兜 (Iron Helmet) +鉄仮面 (Iron Mask) +戦士の兜 (Warrior's Helmet) +猛牛ヘルム (Bull Helm) +玉鋼の兜 (Tamahagane Helmet) +グレートヘルム (Great Helm) +ミスリルヘルム (Mithril Helm) +幻魔の兜 (Phantom Demon Helmet) +女神の兜 (Goddess Helmet) +オルテガの兜 (Ortega's Helmet) +エンデの兜 (Ende's Helmet) +スチルキングヘルム (Steel King Helm) +天空の兜 (Heavenly Helmet) +太陽の冠 (Crown of the Sun) +ロトの兜 (Roto's Helmet) +竜のお守り (Dragon Amulet) +結界の指輪 (Ring of Protection) +護りのルビー (Ruby of Protection) +力のルビー (Ruby of Power) +怒りのタトゥー (Tattoo of Rage) +豪傑の腕輪 (Brave's Bracelet) +はやてのリング (Swift Ring) +疾風のバンダナ (Gale Bandana) +星降る腕輪 (Starfall Bracelet) +インテリめがね (Intelligent Glasses) +博識リング (Knowledge Ring) +知力の腕輪 (Bracelet of Wisdom) +大地の指輪 (Earth Ring) +命の指輪 (Ring of Life) +妖精の腕輪 (Fairy Bracelet) +女神の指輪 (Goddess Ring) +幸運のお守り (Lucky Charm) +ラッキーペンダント (Lucky Pendant) +魔除けの聖印 (Talisman of Protection) +破毒のリング (Antidote Ring) +めざましリング (Awakening Ring) +音溢れの指輪 (Sound Overflow Ring) +理性のリング (Ring of Reason) +エルフのお守り (Elf Charm) +癒しの腕輪 (Healing Bracelet) +祈りの腕輪 (Prayer Bracelet) +静寂の玉 (Orb of Silence) +うさぎのしっぽ (Rabbit's Tail) +銀の指輪 (Silver Ring) +炎のリング (Ring of Fire) +水のリング (Ring of Water) +アバンのしるし (Avan's Emblem) +太陽の指輪 (Ring of the Sun) +月の指輪 (Ring of the Moon) +業師の手袋 (Artisan's Gloves) +達人の手袋 (Master's Gloves) +神業の手袋 (Divine Gloves) +革の靴 (Leather Shoes) +盗賊のブーツ (Thief's Boots) +黄金の靴 (Golden Shoes) +速足のブーツ (Swift Boots) +フェザーシューズ (Feather Shoes) +魔法の靴 (Magic Shoes) +ステルスシューズ (Stealth Shoes) +ヌライムピアス (Nuraim Earrings) +翼のブローチ (Winged Brooch) +世界樹の皮 (World Tree Bark) +ちいさな虫かご (Small Bug Cage) +匂い袋 (Scent Bag) +名人のルアー (Master's Lure) +怪しげなコイン (Suspicious Coin) +謎の鉱物 (Mysterious Mineral) +精霊の腕輪 (Spirit Bracelet) +魔導ユニット (Magic Unit) +竜の角のペンダント (Dragon Horn Pendant) +千里眼の眼鏡 (Clairvoyant Glasses) +幸運の帽子 (Lucky Hat) +修験者の杖 (Ascetic's Staff) +業師の腕輪 (Artisan's Bracelet) +魔物使いの心得 (Beast Tamer's Knowledge) +カイトバックラー (Kite Buckler) +ミスリルシールド (Mithril Shield) +ドルフィンシールド (Dolphin Shield) +聖騎士の盾 (Holy Knight's Shield) +戦士の大盾 (Warrior's Great Shield) +スケイルメイル (Scale Mail) +ホーリーチェイン (Holy Chain) +ルーンスケイル (Rune Scale) +マスターチェイン (Master Chain) +厚手の鎧 (Thick Armor) +ヘヴィアーマー (Heavy Armor) +毛皮のポンチョ (Fur Poncho) +ノーブルマント (Noble Mantle) +ブラックマント (Black Mantle) +マジカルマント (Magical Mantle) +ミラクルマント (Miracle Mantle) +聖者の法衣 (Saint's Robe) +とんがりぼうし (Pointed Hat) +風の帽子 (Wind Hat) +星のサークレット (Star Circlet) +闇夜の帽子 (Dark Night Hat) +アイアンヘッドギア (Iron Headgear) +銀仮面 (Silver Mask) +くろがねのはちがね (Iron Headband) +知力の兜 (Intellect Helm) +ヘヴィヘルム (Heavy Helm) +竜の指輪 (Dragon Ring) +光の指輪 (Light Ring) +闇の指輪 (Dark Ring) +精霊の指輪 (Spirit Ring) + ``` \ No newline at end of file