From 4663bd41806393f1ad0371b2bca0a6e9049104e5 Mon Sep 17 00:00:00 2001 From: dazedanon Date: Sun, 24 Aug 2025 16:23:46 -0500 Subject: [PATCH] dynamically generate vocab file --- modules/rpgmakermvmz.py | 68 +++++++ util/translation.py | 86 ++++++++- vocab.txt | 418 ++++++++++++++++++++++++---------------- 3 files changed, 396 insertions(+), 176 deletions(-) diff --git a/modules/rpgmakermvmz.py b/modules/rpgmakermvmz.py index 4feed3b..3df9f5d 100644 --- a/modules/rpgmakermvmz.py +++ b/modules/rpgmakermvmz.py @@ -251,6 +251,56 @@ def saveProgress(data, filename): traceback.print_exc() +def update_vocab_section(category: str, pairs: list[tuple[str, str]]): + """Update or insert a section in vocab.txt for the given category with provided pairs. + - category: e.g., "Items", "Weapons", etc. Section header will be "# {category}". + - pairs: list of (source, translated) strings. Duplicates by source are deduped (last wins). + The existing section is replaced entirely; other sections are preserved. + """ + try: + vocab_path = Path("vocab.txt") + existing = vocab_path.read_text(encoding="utf-8") if vocab_path.exists() else "" + + # Deduplicate by source term, keep last mapping + dedup: dict[str, str] = {} + for src, dst in pairs: + if not src: + continue + dedup[src] = dst + + lines = [f"{src} ({dst})" for src, dst in dedup.items()] + # Always terminate a section with a blank line to separate from next header + new_block = f"# {category}\n" + "\n".join(lines) + if not new_block.endswith("\n\n"): + if not new_block.endswith("\n"): + new_block += "\n" + new_block += "\n" + + # Regex to find the specific section starting at the header for this category + # and ending right before the next header (any number of '#') or EOF. + # - Handles headers like '#Category', '# Category', '## Category', etc. + # - Uses non-greedy matching for the body to avoid spanning multiple sections. + pattern = re.compile( + rf"^[\t ]*#+\s*{re.escape(category)}\s*$\r?\n.*?(?=^[\t ]*#|\Z)", + re.MULTILINE | re.DOTALL, + ) + if pattern.search(existing): + # Replace only the first matching section for this category + updated = pattern.sub(new_block, existing, count=1) + else: + updated = existing + if updated and not updated.endswith("\n\n"): + # Ensure a blank line before appending new section if file not empty + if not updated.endswith("\n"): + updated += "\n" + updated += "\n" + updated += new_block + + vocab_path.write_text(updated, encoding="utf-8") + except Exception: + traceback.print_exc() + + def parseMap(data, filename): totalTokens = [0, 0] totalLines = 0 @@ -618,6 +668,9 @@ def searchNames(data, pbar, context): profileList = [] nicknameList = [] descriptionList = [] + # Collect name mappings for vocab per run + vocab_pairs: list[tuple[str, str]] = [] + vocab_enabled = context in ["Armors", "Weapons", "Items", "MapInfos", "Classes", "Enemies", "Skills"] # For batching all note types notesBatch = [] # List of (i, regex, match_text, note_type) notesBatchMap = [] # List of (i, regex, match_text, note_type, groupidx) @@ -848,6 +901,7 @@ def searchNames(data, pbar, context): if data[j]["name"] != "": with open("translations.txt", "a", encoding="utf-8") as file: file.write(f'{data[j]["name"]} ({translatedNameBatch[0]})\n') + # Actors are excluded from vocab updates data[j]["name"] = translatedNameBatch[0] translatedNameBatch.pop(0) if "nickname" in data[j] and data[j]["nickname"]: @@ -906,6 +960,11 @@ def searchNames(data, pbar, context): else: # Get Text file.write(f"{data[j]['name']} ({translatedNameBatch[0]})\n") + if vocab_enabled: + try: + vocab_pairs.append((data[j]['name'], translatedNameBatch[0])) + except Exception: + pass data[j]["name"] = translatedNameBatch[0] translatedNameBatch.pop(0) if "description" in data[j] and data[j]["description"] != "": @@ -945,6 +1004,11 @@ def searchNames(data, pbar, context): with open("translations.txt", "a", encoding="utf-8") as file: file.write(f'{data[j]["name"]} ({translatedNameBatch[0]})\n') # Get Text + if vocab_enabled: + try: + vocab_pairs.append((data[j]["name"], translatedNameBatch[0])) + except Exception: + pass data[j]["name"] = translatedNameBatch[0] translatedNameBatch.pop(0) @@ -971,6 +1035,10 @@ def searchNames(data, pbar, context): i += 1 + # Update vocab section once per context after processing all names + if vocab_enabled and vocab_pairs: + update_vocab_section(context, vocab_pairs) + return totalTokens diff --git a/util/translation.py b/util/translation.py index df44165..12996ca 100644 --- a/util/translation.py +++ b/util/translation.py @@ -417,20 +417,86 @@ def elongateCharacters(text): def extractTranslation(translatedTextList, isList, pbar=None): - """Extract translation from JSON response""" + """Extract translation from JSON response. + + This function is resilient to a few common model mistakes: + - Wraps output in code fences or outer quotes + - Uses smart quotes instead of straight quotes + - Inserts an extra leading quote in values (e.g. :""Word" -> :"Word") + - Trailing commas before } or ] + + If strict JSON parsing fails, falls back to a regex-based extractor that + captures LineN values in numeric order. + """ + s = str(translatedTextList or "").strip() + + # Fast exit + if not s: + return None + + # Remove code fences if present + if s.startswith("```"): + s = re.sub(r"^```(?:json)?\s*", "", s, flags=re.IGNORECASE) + s = re.sub(r"\s*```$", "", s) + + # Trim wrapping quotes around the whole JSON blob (common in logs) + if len(s) >= 2 and s[0] == s[-1] and s[0] in {'"', "'"}: + # Only strip if it still looks like JSON inside + if s[1:2] == "{" and s[-2:-1] == "}": + s = s[1:-1] + + # Normalize quotes + s = s.replace("“", '"').replace("”", '"').replace("’", "'") + + # Remove trailing commas before object/array closures + s = re.sub(r",(\s*[}\]])", r"\1", s) + + # Repair common doubled leading quote in values: :""Word" -> :"Word" + # Ensure we don't alter legitimate empty strings (:"") + s = re.sub(r":\s*\"\"(?=[^\",}\]\s])", r':"', s) + + # Attempt strict parse first try: - lineDict = json.loads(translatedTextList) - # If it's a batch (i.e., list), extract with tags; otherwise, return the single item. - stringList = list(lineDict.values()) - if isList: - return stringList + lineDict = json.loads(s) + + # Build list in numeric order if keys are LineN + numeric_keys = [] + for k in lineDict.keys(): + m = re.fullmatch(r"Line(\d+)", str(k)) + if m: + numeric_keys.append(int(m.group(1))) + + if numeric_keys: + stringList = [lineDict.get(f"Line{n}", "") for n in sorted(numeric_keys)] else: - return stringList[0] + # Fallback to values order if no LineN keys found + stringList = list(lineDict.values()) + + return stringList if isList else (stringList[0] if stringList else None) except Exception as e: - if pbar: - pbar.write(f"extractTranslation Error: {e} on String {translatedTextList}") - return None + # Fallback: regex-based extraction tolerant to one or two opening quotes + # Captures escaped quotes within values too + try: + pairs = re.findall(r'"Line(\d+)"\s*:\s*"{1,2}((?:\\.|[^"\\])*)"', s) + if not pairs: + raise ValueError("No LineN pairs found") + + # Sort numerically and unescape JSON string content + items = [] + for n_str, v in sorted(((int(n), v) for n, v in pairs), key=lambda x: x[0]): + try: + # Decode JSON escapes reliably by round-tripping as a JSON string + decoded = json.loads(f'"{v}"') + except Exception: + decoded = v + items.append(decoded) + + return items if isList else (items[0] if items else None) + except Exception as e2: + if pbar: + pbar.write(f"extractTranslation Error: {e2} after JSON error {e} on String {translatedTextList}") + return None def calculateCost(inputTokens, outputTokens, model): diff --git a/vocab.txt b/vocab.txt index 1214f90..491e43f 100644 --- a/vocab.txt +++ b/vocab.txt @@ -165,169 +165,255 @@ w (lol) 『 (『) 』 (』) -# Game Specific -見せかけ場所移動 (Fake Location Move) -撮影用_駅前 (For Filming_Station Front) -__自宅周辺___ (__Around Home__) -撮影用_トレーニングジム (For Filming_Training Gym) -__澪の自室__ (__Mio's Room__) -撮影用_イベントホール (For Filming_Event Hall) -OP_1 (OP_1) -撮影用_アーケード (For Filming_Arcade) -撮影用__神社 (For Filming_Shrine) -OP__教室 (OP_Classroom) -撮影用__ワールドマップ___ (For Filming_World Map___) -___ワールドマップ___ (___World Map___) -イベ用_澪の家の庭 (Event_Mio's Garden) -★回想部屋 (★Recollection Room) -アーケードバックアップ (Arcade Backup) -撮影用_コンビニ (For Filming_Convenience Store) -撮影用_骨董品屋 (For Filming_Antique Shop) -OP__教室2 (OP_Classroom 2) -OP_駅前 (OP_Station Front) -コンビニ (Convenience Store) -撮影用__森林公園 (For Filming_Forest Park) -回想セイラ_パイズリ (Recollection Seira_Titjob) -回想_ルカ手コキ (Recollection_Luka Handjob) -再開発ビル (Redevelopment Building) -撮影用__海岸洞窟 (For Filming_Coastal Cave) -OP_自宅周辺_ (OP_Around Home_) -OP_自宅周辺_2 (OP_Around Home_2) -撮影用_遊園地 (For Filming_Amusement Park) -撮影用__総合病院 (For Filming_General Hospital) -撮影用__ラストダンジョン (For Filming_Last Dungeon) -学校 3階 (School 3F) -再開発ビル2F (Redevelopment Building 2F) -ボス会話1 (Boss Conversation 1) -再開発ビル3F (Redevelopment Building 3F) -撮影用_学校 (For Filming_School) -撮影用_海 (For Filming_Sea) -駅前_夜_撮影用 (Station Front_Night_For Filming) -ひなた救出_自宅周辺_ (Hinata Rescue_Near Home_) -森林公園クリア後_セイラと会話 (After Clearing Forest Park_Talk with Seira) -回想_物置小屋イベ用 (Recollection_Shed Event) -回想_汎用07 (Recollection_Generic 07) -手術室 (Operating Room) -総合病院1Fトイレ (General Hospital 1F Restroom) -イベントホール_初めて入る (Event Hall_First Entry) -OP__神社 (OP_Shrine) -再開発ビル4F (Redevelopment Building 4F) -イベ用___婦警神社の近く (For Event_Near Policewoman Shrine) -OP_澪の自室__ (OP_Mio's Room_) -ナースステーション (Nurse Station) -総合病院3Fトイレ (General Hospital 3F Restroom) -管理室イベ用 (For Event_Control Room) -バックアップ通気口 (Backup Ventilation Duct) -イベントホール_クリア後 (Event Hall_After Clearing) -OP_オープニング2 (OP_Opening 2) -思い出の公園 (Memorial Park) -ルカの部屋 (Luka's Room) -最初_海岸洞窟 (First_Coastal Cave) -森林公園_エリア1 (Forest Park_Area 1) -森林公園エリア2小屋 (Forest Park Area 2_Hut) -図書室で情報聞いた後 (After Getting Info in Library) -イベントホール (Event Hall) -_サマースクール後 (_After Summer School) -ボス会話2 (Boss Conversation 2) -イベントホール_ボス倒した~3章 (Event Hall_Boss Defeated ~ Chapter 3) -サマースクール後_催眠見た後 (After Summer School_After Hypnosis Scene) -思い出の公園_過去 (Memorial Park_Past) -イベ2_プール (Event 2_Pool) -_イベ_学校の女子トイレ (_Event_School Girls' Restroom) -ボス会話3 (Boss Conversation 3) -学校ボス倒した~7章 (School Boss Defeated ~ Chapter 7) -エレベーター内 (Inside Elevator) -ルカの回想_過去 (Luka's Flashback_Past) -ラスボス前会話 (Pre-Final Boss Conversation) -アイドルイベ_駅前_ (Idol Event_Station Front_) -アイドルイベ_イベントホール (Idol Event_Event Hall) -ボーイッシュ女子_ぶっかけ用 (Boyish Girl_For Cumshot) -ボーイッシュ女子_挿入用 (Boyish Girl_For Insertion) -思い出の公園_過去後 (Memorial Park_After the Past) -ゲームオーバー澪の部屋__ (Game Over Mio's Room__) -セイラ_襲う前会話 (Seira_Pre-Attack Conversation) -ラスボス倒した後会話 (Post-Final Boss Conversation) -エンディング真__神社 (True Ending__Shrine) -エンディングセイラ__神社 (Seira Ending__Shrine) -エンディング_ルカ (Ending_Luka) -エンディング_思い出の公園 (Ending_Memorial Park) -ロッカールーム (Locker Room) -イベ_プール (Event_Pool) -プール会話 (Pool Conversation) -回想ルカ_初催眠 (Luka Flashback_First Hypnosis) -回想_ルカ_素股 (Flashback_Luka_Thighjob) -回想_ルカ_全裸 (Recollection_Luka_Nude) -回想_プールで (Recollection_At the Pool) -回想_悪の騎乗 (Recollection_Evil Cowgirl) -回想_ラスボス (Recollection_Final Boss) -回想_ボーイッシュ女子 (Recollection_Boyish Girl) -コンビニのトイレ (Convenience Store Bathroom) -回想_コンビニ店員 (Recollection_Convenience Store Clerk) -回想__婦警 (Recollection_Policewoman) -回想_女子アナ (Recollection_Female Announcer) -回想_アイドル本番 (Recollection_Idol Sex Scene) -回想_ひなた (Recollection_Hinata) -回想_ひなた2 (Recollection_Hinata 2) -回想_セイラ_襲う前会話 (Recollection_Seira_Pre-Attack Conversation) -回想ダン_ダウナー (Recollection_Dan_Downer) -最初テレビ__澪の自室__ (First TV__Mio's Room__) -回想_JD (Recollection_College Girl) -回想ダン_スク水女子 (Recollection_Dan_School Swimsuit Girl) -回想_ナース (Recollection_Nurse) -学校 2階 (School 2F) -回想_ダン_お嬢様系女子 (Recollection_Dan_Ojou-sama Type Girl) -遊園地 (Amusement Park) -ジェットコースター乗り場 (Roller Coaster Platform) -回想_ダン_眼鏡女子 (Recollection_Dan_Glasses Girl) -ひなたイベ_自宅周辺 (Hinata Event_Near Home) -駅前 (In Front of the Station) -学校1階 (School 1F) -図書室 (Library) -屋上 (Rooftop) -回想_OL (Recollection_Office Lady) -女子トイレ (Girls' Bathroom) -プール (Pool) -教室 (Classroom) -回想_ルカ全裸_導入 (Recollection_Luka Nude_Intro) -テンプレ (Template) -海岸 (Beach) -オーケストラフロア (Orchestra Floor) -アーケード (Arcade) -岩場 (Rocky Area) -バックアップ部屋 (Backup Room) -__神社 (__Shrine) -__骨董品屋 (__Antique Shop) -森林公園_エリア2 (Forest Park_Area 2) -森林公園_エリア3 (Forest Park_Area 3) -通気口 (Ventilation Duct) -森林公園_物置小屋 (Forest Park_Storage Shed) -森林公園_物置小屋イベ用 (Forest Park_Storage Shed (Event)) -森林公園エリア4 (Forest Park Area 4) -ライブ会場 (Live Venue) -空きフロア (Empty Floor) -管理室 (Control Room) -女子トイレ (Girls' Restroom) -男子トイレ (Boys' Restroom) -レストラン (Restaurant) -海岸洞窟入口 (Beach Cave Entrance) -海岸洞窟エリア1 (Beach Cave Area 1) -海岸洞窟小部屋 (Beach Cave Small Room) -海岸洞窟エリア2 (Beach Cave Area 2) -海岸洞窟小部屋2 (Beach Cave Small Room 2) -海岸洞窟エリア3 (Beach Cave Area 3) -海岸洞窟エリア4 (Beach Cave Area 4) -お化け屋敷 (Haunted House) -食堂 (Dining Hall) -書斎 (Study) -総合病院2F (General Hospital 2F) -総合病院 (General Hospital) -総合病院3F (General Hospital 3F) -✖エレベーター内_バックアップ (✖Inside Elevator_Backup) -エレベーター内 (Inside Elevator) -病室イベント用 (For Hospital Room Event) -トレーニングジム (Training Gym) -路地裏_ひなた (Back Alley_Hinata) -公衆トイレ_女子アナイベ (Public Restroom_Female Announcer Event) -戦闘テスト (Battle Test) -撮影用_自宅周辺__ (For Filming_Near Home) -撮影用_澪の部屋__ (For Filming_Mio's Room) +# Armors +伊達メガネ (Fake Glasses) +髪飾り (Hair Ornament) +制服 (Uniform) +防毒グローブ (Anti-Toxin Gloves) +琥珀の環 (Amber Ring) +レジストブーツ (Resist Boots) +再生のネックレス (Necklace of Regeneration) +気力のネックレス (Necklace of Willpower) +必勝のお守り (Lucky Charm) + +# Classes +フタナリの勇者 (Futanari Hero) +魔術師_発情時 (Mage (in heat)) +✖?魔術師_発情時(回想用) (✖? Mage (in heat) (for recollection)) +☆魔術師_発情時_防御コマンドバックアップ (☆Mage (in heat) Defense Command Backup) +☆魔術師_魔法バックアップ (☆Mage Magic Backup) +フタナリの勇者_倒れ (Futanari Hero (downed)) + +# Enemies +イビルホーク (Evil Hawk) +毒蛇 (Poison Snake) +暴走イノシシ (Rampaging Boar) +ランニング女子 (Running Girl) +ーー回想ーーーー (Flashbackkkk) +アイドル (Idol) +黒ギャル (Black Gal) +女医 (Female Doctor) +担任 (Homeroom Teacher) +回想用ゴブリン (Flashback Goblin) +回想用メガワーム (Flashback Mega Worm) +セクハラテスト用 (For Sexual Harassment Test) +ーーイベーー (Eventt) +石像 (Statue) +モニュメント (Monument) +ボイドファンガス (Void Fungus) +ーー海ーー (Seaa) +キングクラブ (King Crab) +アクアマンダー (Aquamander) +アビスジェリー (Abyss Jelly) +ーー遊ーー (Playy) +お化けカボチャ (Pumpkin Ghost) +エビルトイ (Evil Toy) +呪いのぬいぐるみ (Cursed Plushie) +フードの女 (Hooded Woman) +ーー病ーー (Hospitall) +ショックランプ (Shock Lamp) +ネイルボルト (Nail Bolt) +メガマウス (Megamouth) +ーー学ーー (--Gaku--) +動く彫刻 (Moving Sculpture) +人体模型 (Anatomical Model) +ーーラーー (--Raa--) +ダークフォーム・ウィスプ (Dark Form Wisp) +ダークフォーム・ヴェイル (Dark Form Veil) +ダークフォーム・アビス (Dark Form Abyss) +魔王妃 (Demon Queen) +バックアップ_YEP_BattleAICoreイビルツリー (Backup_YEP_BattleAICore Evil Tree) +ボス_気合あるバックアップ (Boss_Determined Backup) + +# Items +傷薬 (Healing Potion) +ミネラルウォーター (Mineral Water) +漢方薬 (Herbal Medicine) +高級ミネラルウォーター (Premium Mineral Water) +オロミナンD (Orominan D) +✖自宅へ帰還 (✖Return Home) +オートメッセージ調整 (Auto Message Settings) +ヘルプ (Help) +魔攻のもと (Demon Attack Essence) +MPのもと (MP Essence) +攻撃のもと (Attack Essence) +防御のもと (Defense Essence) +HPのもと (HP Essence) +魔防のもと (Demon Defense Essence) +敏捷のもと (Agility Essence) +幸運のもと (Luck Essence) +MP回復リンゴ (MP Recovery Apple) +門の鍵 (Gate Key) +蝋燭 (Candle) +時計の針 (Clock Hand) +ルカとイベントホールイベ発生前 (Luka & Event Hall (Before Event)) +SP取得テスト (SP Acquisition Test) +戦闘セクハラ表示設定 (Battle Lewd Display Settings) +救急箱 (First Aid Kit) +スキルリセッタ (Skill Resetter) +イビルホークの羽 (Evil Hawk Feather) +毒牙 (Poison Fang) +暴走イノシシの牙 (Rampaging Boar Fang) +モニュメントの欠片 (Monument Fragment) +石像の欠片 (Statue Fragment) +黒い菌糸 (Black Mycelium) +キングクラブの鋏 (King Crab Claw) +アクアマンダーの皮 (Aquamander Hide) +アビスジェリーの足 (Abyss Jelly Leg) +エビルトイの靴 (Evil Toy Shoes) +ぬいぐるみのポーチ (Stuffed Animal Pouch) +お化けカボチャの種 (Ghost Pumpkin Seed) +古い電源コード (Old Power Cord) +錆びた電池 (Rusty Battery) +メガマウスのしっぽ (Megamouth Tail) +石膏 (Plaster) +模型のパーツ (Model Parts) +火の力 (Power of Fire) +氷の力 (Power of Ice) +雷の力 (Power of Thunder) +土の力 (Power of Earth) +光の力 (Power of Light) +\N[3] (\N[3]) +\N[4] (\N[4]) +ランニング女子 (Running Girl) +ダウナー系女子 (Downer-type Girl) +アイドル (Idol) +スク水女子 (School Swimsuit Girl) +黒ギャル (Black Gal) +女子大生 (College Girl) +ボーイッシュ女子 (Boyish Girl) +\V[119] (\V[119]) +女医 (Female Doctor) +お嬢様系女子 (Ojou-sama-type Girl) +眼鏡女子 (Glasses Girl) +担任 (Homeroom Teacher) +OL (Office Lady) +コンビニ店員 (Convenience Store Clerk) +婦警 (Policewoman) +\N[5] (\N[5]) +女子アナウンサー (Female Announcer) +人妻熟女 (Married Mature Woman) +メイド (Maid) +水着女子 (Swimsuit Girl) +酔ったお姉さん (Drunk Older Woman) +\V[129] (\V[129]) +イベントホールイベ発生前 (Event Hall -Before Event Trigger) +ルカとサマースクール中 (With Luka at Summer School) +女子アナイベ見た_スタッフ用 (Announcer Event Seen_Staff Use) +森林公園_初回攻略中 (Forest Park_First Time Clearing) +総合病院マスターキー (General Hospital Master Key) + +# Skills +攻撃 (Attack) +防御 (Defend) +連続攻撃 (Combo Attack) +2回攻撃 (Double Attack) +3回攻撃 (Triple Attack) +逃げる (Escape) +様子を見る (Observe) +ヒール (Heal) +逃走封じ (Escape Seal) +スパーク (Spark) +毒牙 (Poison Fang) +スプリントチャージ (Sprint Charge) +Slash1 30FPS (Slash1 30FPS) +Slash2 30FPS (Slash2 30FPS) +インパクト・ラッシュ (Impact Rush) +黒いモヤ (Black Haze) +強打 (Heavy Blow) +Rage 30FPS (Rage 30FPS) +ファイア (Fire) +岩落とし (Rock Drop) +クラッシュブロウ (Crash Blow) +電撃 (Thunderbolt) +キュア (Cure) +大ばさみ (Great Shears) +ダブルストライク (Double Strike) +アイス (Ice) +アイシクル (Icicle) +ヘイルストーム (Hailstorm) +アクアバースト (Aqua Burst) +汚水噴射 (Sewage Spray) +タイダルクラッシュ (Tidal Crash) +ミラーシールド (Mirror Shield) +アンチバフ (Anti-Buff) +アシストパワー (Assist Power) +アシストガード (Assist Guard) +かまいたち (Razor Wind) +眠り粉 (Sleep Powder) +教鞭のムチ (Teacher's Whip) +勃起 (Erection) +攻撃あ (Attack A) +デバフクリア (Debuff Clear) +ハサミ (Scissors) +マジックスティール (Magic Steal) +聖剣フタナリ説明ウェイト用 (Holy Sword Futanari Explanation (Wait)) +防御あ (Defense A) +魔攻あ (Magic Attack A) +レベル2ダーク (Level 2 Dark) +レベル3ダークボム (Level 3 Dark Bomb) +口 (Mouth) +膣 (Vagina) +アナル (Anal) +回想セクハラ_キス (Recall Lewd Act_Kiss) +戦闘_セクハラ_キス (Battle_Lewd Act_Kiss) +✖回想_発情 (✖Recall_Heat) +回想セクハラ_後ろから胸 (Recall Lewd Act_Breasts from Behind) +回想セクハラ_胸 (Recall Lewd Act_Breasts) +戦闘_セクハラ_胸 (Battle_Lewd Act_Breasts) +戦闘_セクハラ_後ろから胸 (Battle_Lewd Act_Breasts from Behind) +射精 (Ejaculation) +射精後ぐったり (Exhausted After Ejaculation) +✖誘う (✖ Seduce) +✖膣 (✖ Vagina) +✖アナル (✖ Anal) +息を整える (Catch Your Breath) +✖口 (✖ Mouth) +戦闘_セクハラ_尻 (Battle_Sexual Harassment_Ass) +回想セクハラ_尻 (Replay Sexual Harassment_Ass) +戦闘_セクハラ_パンツ越し (Battle_Sexual Harassment_Over Panties) +回想セクハラ_パンツ越し (Replay Sexual Harassment_Over Panties) +戦闘_セクハラ_チン_しごく (Battle_Sexual Harassment_Jerk Off Dick) +回想セクハラ_チン_しごく (Replay Sexual Harassment_Jerk Off Dick) +戦闘_セクハラ_耳_舐め (Battle_Sexual Harassment_Ear Lick) +回想セクハラ_耳舐め (Replay Sexual Harassment_Ear Lick) +体当たり (Body Slam) +毒液 (Poison Liquid) +スキル封じ (Skill Seal) +\V[123]大暴走 (\V[123] Rampage) +邪気集中 (Evil Aura Focus) +フレイムエッジ (Flame Edge) +アイスエッジ (Ice Edge) +サンダーエッジ (Thunder Edge) +ロックエッジ (Rock Edge) +ホーリーエッジ (Holy Edge) +魔防あ (Magic Defense A) +光 (Light) +聖剣フタナリ (Holy Sword Futanari) +メガスラッシュ (Mega Slash) +ダブルソード (Double Sword) +行動力+1 (Action +1) +リベンジストライク (Revenge Strike) +精神統一 (Mental Focus) +高速復帰 (Quick Recovery) +呪いの歌 (Cursed Song) +ソングオブルイン (Song of Ruin) +かぎ爪 (Claw) +展示物落下 (Falling Exhibit) +トライエッジストライク (Tri-Edge Strike) +カウンター (Counter) +弱点追加 (Weakness Added) +電気ショック (Electric Shock) +粉塵爆発 (Dust Explosion) +魅惑の歌 (Enthralling Song) +超振動 (Super Vibration) +マイクスマッシュ (Mic Smash) + +# Weapons +光の剣 (Sword of Light) +アルティメットソード (Ultimate Sword) +杖 (Staff) +弓 (Bow) +スケールワンド (Scale Wand) +聖剣スキル (Holy Sword Skill) +あ (Ah)