diff --git a/build.py b/build.py index b9f52c3..165ac95 100755 --- a/build.py +++ b/build.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import io import logging +import math import os import struct from pathlib import Path @@ -40,7 +41,6 @@ def read_fixed_from_xml(input_file, table, formatter=None): for child in root: text = child.text pointer = Pointer(i) - print(f"{hex(i)}: {text}") formatted_text = formatter(text) if formatter else text pointer.value = table.to_bytes(formatted_text) if text else b"" max_length = max(max_length, len(pointer.value)) @@ -53,7 +53,6 @@ def read_fixed_from_xml(input_file, table, formatter=None): pointer_table.append(pointer) i += 1 - print(f"max {max_length}") return pointer_table @@ -140,10 +139,13 @@ def build_fixed_asset(table, input_file, binary_text_file): pointers = read_fixed_from_xml(input_file, table) write_pointers_value_as_binary(pointers, binary_text_file) -def build_fixed_to_ptr_asset(table, input_file, binary_text_file, pointers_file): - pointers = read_fixed_from_xml(input_file, table, formatter=lambda t: t.strip() + "[end]") - metrics = TextMetrics(table, [Path("./assets/menu_font_length_table.dat").read_bytes()]) +def build_fixed_to_ptr_asset(table, input_file, binary_text_file, pointers_file, buffer_width=None): + pointers = read_fixed_from_xml( + input_file, table, formatter=lambda t: t.strip() + "[end]" + ) + + metrics = TextMetrics(table, ["./assets/menu_font.dat"], char_height=8) max_length = 0 max_ptr = None for i, pointer in enumerate(pointers): @@ -151,13 +153,20 @@ def build_fixed_to_ptr_asset(table, input_file, binary_text_file, pointers_file) if ptr_len > max_length: max_ptr = (i, pointer) max_length = ptr_len + + if buffer_width and ptr_len > buffer_width: + text = table.to_text(pointer.value) + print(f"{text} is too long ({ptr_len}px , {math.ceil(ptr_len / 8)} tiles)") + text = table.to_text(max_ptr[1].value) + print(f"{text} is the largest ({max_length}px ({math.ceil(max_length/8)})") write_pointers_value_as_binary(pointers, binary_text_file) write_pointers_addresses_as_binary( pointers, lambda x: struct.pack(" None: + +def build_null_terminated_with_base( + table: Table, input_file: str, binary_file: str, base: int +) -> None: pointers = read_stringarray_from_xml(input_file, table) pointers_bytes = io.BytesIO() @@ -176,7 +188,7 @@ def build_null_terminated_with_base(table: Table, input_file: str, binary_file:s for pointer in pointers: value = pointer.get_value() - pointers_bytes.write(struct.pack(" None: - chars = table.to_bytes(text) + if data_path.stem == "menu_font": + overrides = {0xFF: 3} + else: + overrides = { + 0xFF: 3 if data_path.stem == "font" else 5, + 0xFD: 1, + 0xFE: 2, + 0xA0: -1, + } - kerning_pairs[(chars[0], chars[1])] = advance + len_table, data = converter.convert_to_1bpp(width_overrides=overrides) - add_custom_kernings("tt", 2) + # Generate test pairs (common kerning candidates) + known_pairs_to_kern = [] - kerning_pairs = converter.find_kerning_pairs(table, known_pairs_to_kern) + # Uppercase + lowercase (classic kerning pairs) + letters = ["T", "V", "F", "P", "A", "W", "Y", "L", "v", "t", "f", "r"] + vowels = ["a", "e", "i", "o", "u", "é", "à", "â", "è", "ê", "ï", "îr"] + + if data_path.stem != "menu_font": + for letter in letters: + for vowel in vowels: + known_pairs_to_kern.append(letter + vowel) + + # Lowercase + descender + for vowel in vowels + ["n"]: + known_pairs_to_kern.append(vowel + "j") + known_pairs_to_kern.append(vowel + "g") + known_pairs_to_kern.append(vowel + "y") + known_pairs_to_kern.append(vowel + "t") + known_pairs_to_kern.append(vowel + "f") + + # Common letter combinations that might benefit + common_pairs = ["rn", "fi", "fl", "ff", "tt", "ll"] + known_pairs_to_kern.extend(common_pairs) + known_pairs_to_kern.extend( + ["ît", "aî", "va", "ïe", "în", "bî", "îm", "Îl", "aï", "ïm"] + ) + print( + f"Testing {len(known_pairs_to_kern)} potential kerning pairs in {Path(font_file).stem}..." + ) + # known_pairs_to_kern = ["Ta"] + # Find pairs that benefit from kerning + kerning_pairs = converter.find_kerning_pairs(table, known_pairs_to_kern) + + def add_custom_kernings(text: str, advance: int) -> None: + chars = table.to_bytes(text) + + kerning_pairs[(chars[0], chars[1])] = advance + + add_custom_kernings("tt", 2) + else: + known_pairs_to_kern = [ + "Ya", + "Pa", + "Po" + "Fa", + "Fe", + "Fo", + "Fu", + "Ta", + "Te", + "To", + "Tu", + "Tr", + "Ts", + "ra", + "re", + "ro", + "Aï", + "ïe", + "aî", + "ît", + "pa", + "at", + "ta", + "te", + "nt", + "fa", + "fe", + "fo", + "fu", + "fi", + "st", + "va", + ] + kerning_pairs = converter.find_kerning_pairs(table, known_pairs_to_kern) with open(data_file, "wb") as fd: fd.write(data) + + # Write kerning data immediately after character data count = len(kerning_pairs) fd.write(struct.pack(" None: "nullterminated": build_null_terminated, "nullterminated_with_base": build_null_terminated_with_base, "vwf-font": build_vwf_font_asset, - "vwf-font-2bpp": build_vwf_font_asset_2bpp, } @@ -356,7 +419,7 @@ def build_assets(assets): "assets/font.dat", "assets/font_length_table.dat", 16, - dialog_table + dialog_table, ), ( "vwf-font", @@ -365,7 +428,7 @@ def build_assets(assets): "assets/bold_font.dat", "assets/bold_font_length_table.dat", 16, - dialog_table + dialog_table, ), ( "vwf-font", @@ -374,7 +437,7 @@ def build_assets(assets): "assets/wicked_font.dat", "assets/wicked_font_length_table.dat", 16, - dialog_table + dialog_table, ), ( "vwf-font", @@ -383,15 +446,16 @@ def build_assets(assets): "assets/book_font.dat", "assets/book_font_length_table.dat", 16, - dialog_table + dialog_table, ), ( - "vwf-font-2bpp", - "fonts/8x8vwf2p.png", - True, + "vwf-font", + "fonts/8x8vwf.png", + False, "assets/menu_font.dat", "assets/menu_font_length_table.dat", 8, + menu_table, ), ("fixed", menu_table, os.path.join(text_root, "items.xml"), "assets/items.dat"), ("fixed", menu_table, os.path.join(text_root, "magic.xml"), "assets/magic.dat"), @@ -413,12 +477,27 @@ def build_assets(assets): os.path.join(text_root, "battle_commands.xml"), "assets/battle_commands.dat", ), + ( + "fixed_to_ptr", + menu_table, + os.path.join(text_root, "battle_commands.xml"), + "assets/battle_commands_nul.dat", + "assets/battle_commands_nul.ptr", + ), ( "fixed_to_ptr", menu_table, os.path.join(text_root, "attack-names.xml"), "assets/attack_names.dat", - "assets/attack_names.ptr" + "assets/attack_names.ptr", + ), + ( + "fixed_to_ptr", + menu_table, + os.path.join(text_root, "monsters_long.xml"), + "assets/monsters_long.dat", + "assets/monsters_long.ptr", + 80 ), ( "nullterminated", @@ -439,13 +518,12 @@ def build_assets(assets): "assets/classes.dat", "assets/classes.ptr", ), - ( "nullterminated_with_base", menu_table, os.path.join(text_root, "battle_statuses.xml"), "assets/battle_statuses.dat", - 0x27b000 + 0x27B000, ), ] @@ -453,7 +531,7 @@ def build_assets(assets): credits_file = Path(f"./text/{lang}/credits.txt") menu_table.parse_table_line("0A=.") - del menu_table.lookup[".."] + # del menu_table.lookup[".."] credits_text = credits_file.read_text() credits_lines = credits_text.split("\n") @@ -484,11 +562,6 @@ def build_assets(assets): k += 2 translated_gfx.write_bytes(output_buffer) - small_text = ["Niveau", "Gils"] - - generate_8x8_vwf_asset(small_text, "vwf_precomp", 0x90) - menu_vwf_table = Table("text/vwf_precomp.tbl") - with open("assets/dakuten.bin", "wb") as fd: fd.write(generate_dakutens(menu_table)) diff --git a/ff4.s b/ff4.s index c5222ef..072786f 100644 --- a/ff4.s +++ b/ff4.s @@ -1,14 +1,19 @@ ; ---------------- ; Final Fantasy IV the new hack. ; ---------------- - +DEBUG := 1 ; Feature Flips ENABLE_DIALOG_SKIP := 1 ENABLE_INTRO := 1 ENABLE_VWF_ATTACK_NAMES := 1 BATTLE_ENABLED := 1 MAGIC_ENABLED := 1 - +ENABLE_KERNING := 1 +ENABLE_KERNING_MENU := 0 +ENABLE_BUTTON_DISPLAY := 1 +BATTLE_CMD_VWF := 1 +BATTLE_NAMES_VWF := 1 +BATTLE_MONSTERS_VWF := 1 ; Debug flags TRIGGER_ENDING_CUTSCENE := 0 @@ -24,7 +29,12 @@ TRIGGER_ENDING_CUTSCENE := 0 } .include 'src/battle/message_patches.s' .include 'src/battle/sram_patches.s' + +.if BATTLE_MONSTERS_VWF { + .include 'src/battle/monsters_patches.s' +} } + .include 'src/places_names.s' .include 'src/new_game.s' .include 'src/credits.s' @@ -45,7 +55,7 @@ dialog_bank_ptr_base = 0x218000 *=0xFFD6 .db 0x02 ; Cartridge Type .db 0x0B ; ~ 0BH ROM Size - .db 0x06 ; RAM Size + .db 0x07 ; RAM Size @@ -91,12 +101,11 @@ clear_ram: _loop: sta.l 0x702000, x inx - cpx.w #0x4000 + cpx.w #0x5000 bne _loop } rtl -; .include 'src/libmz.s' .if ENABLE_INTRO { .include 'src/intro.s' @@ -108,9 +117,11 @@ _loop: .include 'src/battle/sram.s' .include 'src/battle/message.s' .include 'src/battle/graphics.s' + .include 'src/battle/monsters_reloc.s' .if MAGIC_ENABLED { .include 'src/battle/magic/reloc.s' } + .include 'src/battle/commands_reloc.s' } .include 'src/dialog.s' .include 'src/places_names_window.s' @@ -125,6 +136,10 @@ _loop: .incbin 'assets/attack_names.ptr' .incbin 'assets/attack_names.dat' + .incbin 'assets/monsters_long.ptr' + .incbin 'assets/monsters_long.dat' + .incbin 'assets/battle_commands_nul.ptr' + .incbin 'assets/battle_commands_nul.dat' .incbin 'assets/magic.dat' .incbin 'assets/places_names.dat' .incbin 'assets/classes.ptr' @@ -150,7 +165,6 @@ _loop: *=0x288000 .incbin 'assets/menu_font.dat' - .incbin 'assets/menu_font_length_table.dat' .incbin 'assets/font.dat' .incbin 'assets/wicked_font.dat' .incbin 'assets/book_font.dat' @@ -186,5 +200,4 @@ font_table: lda #0x39 nop } - - +;end diff --git a/fonts/8x8.bin b/fonts/8x8.bin index 13ef17d..3a4b5ff 100644 Binary files a/fonts/8x8.bin and b/fonts/8x8.bin differ diff --git a/fonts/8x8vwf.png b/fonts/8x8vwf.png index b335041..5b34bd4 100644 Binary files a/fonts/8x8vwf.png and b/fonts/8x8vwf.png differ diff --git a/fonts/8x8vwf2p.png b/fonts/8x8vwf2p.png deleted file mode 100644 index ed67bfa..0000000 Binary files a/fonts/8x8vwf2p.png and /dev/null differ diff --git a/fonts/book_vwf.png b/fonts/book_vwf.png index b090b02..60c92f6 100644 Binary files a/fonts/book_vwf.png and b/fonts/book_vwf.png differ diff --git a/fonts/vwf.png b/fonts/vwf.png index d1aa03f..f48bc08 100644 Binary files a/fonts/vwf.png and b/fonts/vwf.png differ diff --git a/format_bank_xml.py b/format_bank_xml.py index e8c425f..2fc6aae 100755 --- a/format_bank_xml.py +++ b/format_bank_xml.py @@ -13,6 +13,7 @@ from metrics import TextMetrics WINDOW_WIDTH = 208 +FOURTH_LINE_WIDTH = 200 # Fourth line is 8 pixels shorter class Token: @@ -30,6 +31,7 @@ def __init__(self): self.character_pattern = re.compile(r"(\w+(?:\s+\w+)*):") self.guillemet_pattern = re.compile(r"«([^»]*)»") self.end_pattern = re.compile(r"\[end\]") + self.close_window_pattern = re.compile(r"\[close_window\]") def tokenize(self, text): tokens = [] @@ -54,6 +56,13 @@ def tokenize(self, text): i = end_match.end() continue + # Check for [close_window] marker + close_window_match = self.close_window_pattern.match(text, i) + if close_window_match: + tokens.append(Token("CLOSE_WINDOW", "[close_window]", i)) + i = close_window_match.end() + continue + # Check for guillemet speech guillemet_match = self.guillemet_pattern.match(text, i) if guillemet_match: @@ -78,10 +87,13 @@ def tokenize(self, text): sentence = "" while i < len(text): - # Check if we hit [end] at current position (only [end], not other control codes) - if text[i: i + 5] == "[end]" and sentence.strip(): + # Check if we hit [end] or [close_window] at current position + if text[i : i + 5] == "[end]" and sentence.strip(): # We found [end] and we already have some sentence content break + if text[i : i + 14] == "[close_window]" and sentence.strip(): + # We found [close_window] and we already have some sentence content + break # Check if we hit a guillemet at current position if text[i] == "«" and sentence.strip(): @@ -108,7 +120,11 @@ def tokenize(self, text): # Look ahead to see if this ends the sentence if i >= len(text): # End of text break - elif text[i: i + 5] == "[end]": # Followed by [end] (special case) + elif text[i : i + 5] == "[end]": # Followed by [end] (special case) + break + elif ( + text[i : i + 14] == "[close_window]" + ): # Followed by [close_window] (special case) break elif i < len(text) and text[i] == "[": # Check if this is followed by a control code (not [end]) @@ -116,15 +132,15 @@ def tokenize(self, text): # Find the closing bracket bracket_end = text.find("]", i) if bracket_end != -1: - control_code = text[i: bracket_end + 1] - if control_code != "[end]": + control_code = text[i : bracket_end + 1] + if control_code not in ["[end]", "[close_window]"]: # This is a control code, include it in the sentence but don't consume following spaces - sentence += text[i: bracket_end + 1] + sentence += text[i : bracket_end + 1] i = bracket_end + 1 # Don't consume the space - let the main loop handle it continue else: - # This is [end], break here + # This is [end] or [close_window], break here break elif i < len(text) and text[i].isspace(): # Check if next non-space character is uppercase or special pattern @@ -133,10 +149,11 @@ def tokenize(self, text): j += 1 if j < len(text): if ( - text[j].isupper() - or text[j: j + 1] == "«" - or self.character_pattern.match(text, j) - or text[j: j + 5] == "[end]" + text[j].isupper() + or text[j : j + 1] == "«" + or self.character_pattern.match(text, j) + or text[j : j + 5] == "[end]" + or text[j : j + 14] == "[close_window]" ): break else: @@ -155,32 +172,103 @@ def __init__(self, text_metrics=None): # Initialize TextMetrics if not provided if text_metrics is None: try: - normal_length_table = Path("assets/font_length_table.dat").read_bytes() - bold_length_table = Path("assets/bold_font_length_table.dat").read_bytes() - book_length_table = Path("assets/book_font_length_table.dat").read_bytes() - wicked_length_table = Path("assets/wicked_font_length_table.dat").read_bytes() table = Table("text/ff4fr.tbl") - self.text_metrics = TextMetrics(table, [normal_length_table, wicked_length_table, bold_length_table, - book_length_table]) + + # Use new interleaved format with correct font order + font_files = [ + "assets/font.dat", # Index 0: [normal] (fe 00) + "assets/wicked_font.dat", # Index 1: [wicked] (fe 01) + "assets/book_font.dat", # Index 2: [book/force_book] (fe 02) + "assets/bold_font.dat", # Index 3: [bold] (fe 03) + ] + + self.text_metrics = TextMetrics(table, font_files, char_height=16) except (FileNotFoundError, Exception): # Fallback to None if metrics can't be loaded (for testing) self.text_metrics = None else: self.text_metrics = text_metrics + # Initialize font state tracking + self.reset_font_context() + + def reset_font_context(self): + """Reset font context to default state for processing a new pointer.""" + self.current_font_index = ( + 0 # Track current font index (0=normal, 1=wicked, 2=book, 3=bold) + ) + def parse(self, tokens): - """Parse tokens into dialog segments with intelligent grouping.""" + """Parse tokens and inject WINDOW_BREAK tokens for guillemet speech transitions.""" + # First pass: inject WINDOW_BREAK tokens for guillemet transitions + enhanced_tokens = self._inject_window_breaks(tokens) + + # Second pass: process the enhanced tokens for dialog formatting + return self._format_dialog(enhanced_tokens) + + def _inject_window_breaks(self, tokens): + """Inject WINDOW_BREAK tokens where guillemet speeches should create new windows.""" + enhanced_tokens = [] + + for i, token in enumerate(tokens): + # Add the current token + enhanced_tokens.append(token) + + # Check if we need to add WINDOW_BREAK after this token + if token.type == "GUILLEMET_SPEECH": + # Add WINDOW_BREAK after guillemet speech if there's a next dialog token + # and it's not immediately followed by END or CLOSE_WINDOW + if ( + i + 1 < len(tokens) + and tokens[i + 1].type + in ["CHARACTER", "GUILLEMET_SPEECH", "SENTENCE"] + and tokens[i + 1].type not in ["END", "CLOSE_WINDOW"] + ): + enhanced_tokens.append(Token("WINDOW_BREAK", "[window_break]")) + + elif token.type == "SENTENCE" and i > 0: + # Add WINDOW_BREAK after character speech if followed by guillemet + # First, find if we're in a character context by looking backwards + in_character_context = False + for j in range(i - 1, -1, -1): + if tokens[j].type == "CHARACTER": + in_character_context = True + break + elif tokens[j].type in ["GUILLEMET_SPEECH", "END", "CLOSE_WINDOW"]: + break + + if in_character_context: + # Look ahead to see if followed by guillemet speech + if i + 1 < len(tokens) and tokens[i + 1].type == "GUILLEMET_SPEECH": + enhanced_tokens.append(Token("WINDOW_BREAK", "[window_break]")) + + return enhanced_tokens + + def _format_dialog(self, tokens): + """Format dialog tokens into final output, handling WINDOW_BREAK tokens.""" result = [] current_character = None accumulated_sentences = [] accumulated_text = "" - accumulated_lines = 0 i = 0 while i < len(tokens): token = tokens[i] - if token.type == "CHARACTER": + if token.type == "WINDOW_BREAK": + # Flush accumulated sentences with [new] and reset state + if accumulated_sentences: + result.extend( + self._flush_pre_wrapped_sentences( + accumulated_sentences, add_new=True + ) + ) + accumulated_sentences = [] + accumulated_text = "" + current_character = None + i += 1 + + elif token.type == "CHARACTER": # Character change - process any accumulated sentences first if accumulated_sentences: # Always add [new] when character changes (except for the very first character) @@ -192,7 +280,6 @@ def parse(self, tokens): ) accumulated_sentences = [] accumulated_text = "" - accumulated_lines = 0 current_character = "[bold]" + token.value + "[normal]" i += 1 @@ -208,8 +295,10 @@ def parse(self, tokens): ) # Apply word wrapping to this sentence immediately - wrapped_sentence = self.text_metrics.word_warp( - sentence, WINDOW_WIDTH + wrapped_sentence, self.current_font_index = ( + self.text_metrics.word_warp( + sentence, WINDOW_WIDTH, self.current_font_index + ) ) # Check if adding this wrapped sentence would exceed 4-line limit @@ -219,44 +308,37 @@ def parse(self, tokens): wrapped_sentence ] combined_wrapped_text = "\n".join(all_wrapped_sentences) - lines_needed = self._measure_lines_wrapped( - combined_wrapped_text - ) - - if lines_needed <= 4: + if self._fits_in_dialog_window(combined_wrapped_text): # Fits in current dialog box accumulated_sentences.append(wrapped_sentence) accumulated_text = combined_wrapped_text - accumulated_lines = lines_needed else: # Would exceed limit - flush accumulated with [new] at end, then start new if accumulated_sentences: + # Always add [new] for overflow (readability) + add_new = True result.extend( self._flush_pre_wrapped_sentences( - accumulated_sentences, add_new=True + accumulated_sentences, add_new=add_new ) ) # Start new accumulation with this wrapped sentence accumulated_sentences = [wrapped_sentence] accumulated_text = wrapped_sentence - accumulated_lines = self._measure_lines_wrapped( - wrapped_sentence - ) else: # First sentence for this character accumulated_sentences.append(wrapped_sentence) accumulated_text = wrapped_sentence - accumulated_lines = self._measure_lines_wrapped( - wrapped_sentence - ) else: - # Narrative sentence + # Narrative sentence - use current font context sentence = token.value - # Apply word wrapping to narrative sentences too - wrapped_sentence = self.text_metrics.word_warp( - sentence, WINDOW_WIDTH + # Apply word wrapping with current font context + wrapped_sentence, self.current_font_index = ( + self.text_metrics.word_warp( + sentence, WINDOW_WIDTH, self.current_font_index + ) ) # Apply same intelligent grouping for narrative using wrapped sentences @@ -266,36 +348,27 @@ def parse(self, tokens): wrapped_sentence ] combined_wrapped_text = "\n".join(all_wrapped_sentences) - lines_needed = self._measure_lines_wrapped( - combined_wrapped_text - ) - - if lines_needed <= 4: + if self._fits_in_dialog_window(combined_wrapped_text): accumulated_sentences.append(wrapped_sentence) accumulated_text = combined_wrapped_text - accumulated_lines = lines_needed else: # Would exceed limit - flush accumulated with [new] at end, then start new if accumulated_sentences: + # Always add [new] for overflow (readability) + add_new = True result.extend( self._flush_pre_wrapped_sentences( - accumulated_sentences, add_new=True + accumulated_sentences, add_new=add_new ) ) # Start new accumulation with this wrapped sentence accumulated_sentences = [wrapped_sentence] accumulated_text = wrapped_sentence - accumulated_lines = self._measure_lines_wrapped( - wrapped_sentence - ) else: # First narrative sentence accumulated_sentences.append(wrapped_sentence) accumulated_text = wrapped_sentence - accumulated_lines = self._measure_lines_wrapped( - wrapped_sentence - ) i += 1 @@ -303,22 +376,27 @@ def parse(self, tokens): # Flush any accumulated sentences first if accumulated_sentences: result.extend( - self._flush_pre_wrapped_sentences( - accumulated_sentences, add_new=True - ) + self._flush_pre_wrapped_sentences(accumulated_sentences) ) accumulated_sentences = [] accumulated_text = "" - accumulated_lines = 0 - # Check if this guillemet is followed immediately by [end] - is_followed_by_end = i + 1 < len(tokens) and tokens[i + 1].type == "END" + # Apply word wrapping to guillemet speech + wrapped_guillemet, self.current_font_index = ( + self.text_metrics.word_warp( + token.value, WINDOW_WIDTH, self.current_font_index + ) + ) + + # Check if next token is WINDOW_BREAK to determine if we need [new] + next_is_window_break = ( + i + 1 < len(tokens) and tokens[i + 1].type == "WINDOW_BREAK" + ) - # Add guillemet speech as separate dialog box - if is_followed_by_end: - result.append(token.value) # Don't add [new] if followed by [end] + if next_is_window_break: + result.append(wrapped_guillemet + "[new]") else: - result.append(token.value + "[new]") + result.append(wrapped_guillemet) current_character = None # Reset character context i += 1 @@ -344,7 +422,29 @@ def parse(self, tokens): current_character = None accumulated_sentences = [] accumulated_text = "" - accumulated_lines = 0 + i += 1 + + elif token.type == "CLOSE_WINDOW": + # Close window marker - flush accumulated and add close window marker, then reset state + if accumulated_sentences: + # Add [close_window] to the last accumulated sentence + last_sentence = accumulated_sentences[-1] + accumulated_sentences[-1] = last_sentence + "[close_window]" + result.extend( + self._flush_pre_wrapped_sentences(accumulated_sentences) + ) + accumulated_sentences = [] # Clear to prevent double processing + elif result: + # No accumulated sentences, but we have previous results - append [close_window] to the last result + result[-1] = result[-1] + "[close_window]" + else: + # No accumulated sentences and no previous results - this is a standalone [close_window] + result.append("[close_window]") + + # Reset all state after [close_window] + current_character = None + accumulated_sentences = [] + accumulated_text = "" i += 1 else: @@ -356,12 +456,57 @@ def parse(self, tokens): return result + def _is_next_token_end(self, tokens, current_index): + """Check if the next token is END or CLOSE_WINDOW""" + return current_index + 1 < len(tokens) and tokens[current_index + 1].type in [ + "END", + "CLOSE_WINDOW", + ] + + def _will_character_end_with_end_token(self, tokens, character_index): + """Check if the upcoming character speech will end with an END or CLOSE_WINDOW token""" + # Look ahead from the character token to find where this character's speech ends + i = character_index + 1 + while i < len(tokens): + token = tokens[i] + if token.type in ["END", "CLOSE_WINDOW"]: + return True + elif token.type == "CHARACTER" or token.type == "GUILLEMET_SPEECH": + # Another character or guillemet starts, so this character won't end with END/CLOSE_WINDOW + return False + i += 1 + # Reached end of tokens without finding END/CLOSE_WINDOW or another character + return False + def _measure_lines_wrapped(self, wrapped_text): """Measure how many lines the already-wrapped text takes by counting newlines.""" if not wrapped_text: return 0 return wrapped_text.count("\n") + 1 + def _fits_in_dialog_window(self, wrapped_text): + """Check if the wrapped text fits in a dialog window considering the fourth line is 8 pixels shorter.""" + if not wrapped_text: + return True + + lines = wrapped_text.split("\n") + num_lines = len(lines) + + # More than 4 lines never fits + if num_lines > 4: + return False + + # If we have exactly 4 lines, check if the fourth line fits in the reduced width + if num_lines == 4: + fourth_line = lines[3] + # Measure the fourth line width using current font context + fourth_line_width = self.text_metrics.measure_string(fourth_line) + if fourth_line_width > FOURTH_LINE_WIDTH: + return False + + # 3 or fewer lines, or 4 lines where the fourth line fits + return True + def _flush_pre_wrapped_sentences(self, wrapped_sentences, add_new=False): """Flush pre-wrapped sentences without re-wrapping them.""" if not wrapped_sentences: diff --git a/metrics.py b/metrics.py index f9a0382..8595e93 100644 --- a/metrics.py +++ b/metrics.py @@ -1,27 +1,59 @@ from script import Table +from pathlib import Path +import struct class TextMetrics: - def __init__(self, table: Table, length_tables: list[bytes]): + def __init__(self, table: Table, font_files: list[str], char_height: int = 16): self.table = table - # self.length_table = length_table - self.length_tables = length_tables + self.font_files = font_files + self.char_height = char_height + + # Load new interleaved format + self.length_tables = [] + self.kerning_tables = [] + for font_file in font_files: + length_table, kerning_table = self._load_interleaved_font( + font_file, char_height + ) + self.length_tables.append(length_table) + self.kerning_tables.append(kerning_table) def measure_bytes(self, binary: bytes) -> int: size = 0 k = 0 current_font_index = 0 + prev_char = None + while k < len(binary): char = binary[k] match char: - case 0xfe: + case 0xFE: k += 1 current_font_index = binary[k] + prev_char = None # Reset previous char on font change case 0x4: k += 1 size += 6 * 8 + prev_char = None # Reset previous char after special sequence case _: - size += self.length_tables[current_font_index][char] + 1 + # Add character width + char_width = self.length_tables[current_font_index][char] + size += char_width + + # Add spacing (default 1 pixel, adjusted by kerning) + spacing = 1 + if prev_char is not None: + # Check for kerning adjustment + kerning_pair = (prev_char, char) + if kerning_pair in self.kerning_tables[current_font_index]: + kerning_value = self.kerning_tables[current_font_index][ + kerning_pair + ] + spacing = kerning_value + 1 # Kerning + 1 = actual spacing + + size += spacing + prev_char = char k += 1 @@ -31,51 +63,146 @@ def measure_string(self, line: str) -> int: binary_line = self.table.to_bytes(line) return self.measure_bytes(binary_line) - def word_warp(self, line: str, max_pixel_width: int) -> str: + def word_warp( + self, line: str, max_pixel_width: int, start_font_index: int = 0 + ) -> tuple[str, int]: breaking_chars = b"\xff" binary_line = self.table.to_bytes(line) binary_breaked_line = b"" current_line_pixel_width = 0 index = 0 + current_font_index = start_font_index # Start with provided font index + prev_char = None # Reset previous character for each new string - space_width = self.measure_string(" ") + 1 + # Calculate space width with current font context + space_char = 0xFF # Space character + space_width = self.length_tables[current_font_index][space_char] + 1 while index < len(binary_line): next_break_point = binary_line.find(breaking_chars, index) if next_break_point != -1: next_word = binary_line[index:next_break_point] - next_word_pixel_length = self.measure_bytes(next_word) + # Measure word with current font context + next_word_pixel_length = self._measure_bytes_with_context( + next_word, current_font_index, prev_char + ) + if current_line_pixel_width + next_word_pixel_length >= max_pixel_width: current_line_pixel_width = next_word_pixel_length binary_breaked_line += b"\x01" - + prev_char = None # Reset after line break else: if current_line_pixel_width > 0: binary_breaked_line += b"\xff" current_line_pixel_width += next_word_pixel_length + space_width + prev_char = 0xFF # Space character + binary_breaked_line += next_word + # Update font context and prev_char after processing word + current_font_index, prev_char = self._update_context_after_bytes( + next_word, current_font_index, prev_char + ) + + # Recalculate space width for new font context + space_width = self.length_tables[current_font_index][space_char] + 1 + index = next_break_point + 1 else: # No more break points, process remaining text remaining_word = binary_line[index:] if remaining_word: - remaining_word_pixel_length = self.measure_bytes(remaining_word) + remaining_word_pixel_length = self._measure_bytes_with_context( + remaining_word, current_font_index, prev_char + ) if index > 0: if ( - current_line_pixel_width + remaining_word_pixel_length - >= max_pixel_width + current_line_pixel_width + remaining_word_pixel_length + >= max_pixel_width ): binary_breaked_line += b"\x01" else: binary_breaked_line += b"\xff" binary_breaked_line += remaining_word + # Update font context after processing remaining word + current_font_index, prev_char = self._update_context_after_bytes( + remaining_word, current_font_index, prev_char + ) break - return self.table.to_text(binary_breaked_line) + return self.table.to_text(binary_breaked_line), current_font_index + + def _measure_bytes_with_context( + self, binary: bytes, font_index: int, prev_char: int = None + ) -> int: + """Measure bytes with given font context and previous character.""" + size = 0 + k = 0 + current_font_index = font_index + + while k < len(binary): + char = binary[k] + match char: + case 0xFE: + k += 1 + current_font_index = binary[k] + prev_char = None # Reset previous char on font change + case 0x4: + k += 1 + size += 6 * 8 + prev_char = None # Reset previous char after special sequence + case 0x8: + size = 4 * 8 # Assume 4 full chars for gils count. + prev_char = None + case _: + # Add character width + char_width = self.length_tables[current_font_index][char] + size += char_width + + # Add spacing (default 1 pixel, adjusted by kerning) + spacing = 1 + if prev_char is not None: + # Check for kerning adjustment + kerning_pair = (prev_char, char) + if kerning_pair in self.kerning_tables[current_font_index]: + kerning_value = self.kerning_tables[current_font_index][ + kerning_pair + ] + spacing = kerning_value + 1 # Kerning + 1 = actual spacing + + size += spacing + prev_char = char + + k += 1 + + return size + + def _update_context_after_bytes( + self, binary: bytes, font_index: int, prev_char: int = None + ) -> tuple[int, int]: + """Update font context and prev_char after processing bytes.""" + k = 0 + current_font_index = font_index + + while k < len(binary): + char = binary[k] + match char: + case 0xFE: + k += 1 + current_font_index = binary[k] + prev_char = None + case 0x4: + k += 1 + prev_char = None + case _: + prev_char = char + + k += 1 + + return current_font_index, prev_char def measure_line_count(self, line: str, max_pixel_width: int) -> int: breaking_chars = b"\xff" @@ -84,7 +211,11 @@ def measure_line_count(self, line: str, max_pixel_width: int) -> int: lines_count = 0 current_line_pixel_width = 0 index = 0 - space_width = self.measure_string(" ") + 1 + current_font_index = 0 # Always start with normal font (index 0) + space_char = 0xFF # Space character + space_width = self.length_tables[current_font_index][space_char] + 1 + + prev_char = None while index < len(binary_line): next_break_point = binary_line.find(breaking_chars, index) @@ -92,24 +223,97 @@ def measure_line_count(self, line: str, max_pixel_width: int) -> int: if next_break_point != -1: next_word = binary_line[index:next_break_point] - next_word_pixel_length = self.measure_bytes(next_word) + # Measure word with current font context + next_word_pixel_length = self._measure_bytes_with_context( + next_word, current_font_index, prev_char + ) + if current_line_pixel_width + next_word_pixel_length >= max_pixel_width: current_line_pixel_width = next_word_pixel_length lines_count += 1 + prev_char = None # Reset after line break else: current_line_pixel_width += next_word_pixel_length + space_width + prev_char = 0xFF # Space character + + # Update font context after processing word + current_font_index, prev_char = self._update_context_after_bytes( + next_word, current_font_index, prev_char + ) + + # Recalculate space width for new font context + space_width = self.length_tables[current_font_index][space_char] + 1 index = next_break_point + 1 else: # No more break points, process remaining text remaining_word = binary_line[index:] if remaining_word: - remaining_word_pixel_length = self.measure_bytes(remaining_word) + remaining_word_pixel_length = self._measure_bytes_with_context( + remaining_word, current_font_index, prev_char + ) if ( - current_line_pixel_width + remaining_word_pixel_length - >= max_pixel_width + current_line_pixel_width + remaining_word_pixel_length + >= max_pixel_width ): lines_count += 1 break return lines_count + 1 + + def _load_interleaved_font( + self, font_file: str, char_height: int = 16 + ) -> tuple[bytes, dict]: + """Load font data in the new interleaved format with kerning after character data.""" + try: + with open(font_file, "rb") as f: + font_data = f.read() + except FileNotFoundError: + # Return empty tables if font file doesn't exist + return bytes(256), {} + + # Extract character width data from interleaved format + length_table = bytearray(256) + bytes_per_char = char_height + 1 + + for char_index in range(256): + data_offset = char_index * bytes_per_char + width_offset = data_offset + char_height + + if width_offset < len(font_data): + length_table[char_index] = font_data[width_offset] + else: + length_table[char_index] = 8 # Default width + + kerning_table = {} + kerning_offset = 256 * (char_height + 1) + + if len(font_data) > kerning_offset + 2: + # Check if there's actually kerning data at this offset + # Read potential kerning count and validate it's reasonable + try: + kerning_count = struct.unpack( + " 0 else 0 + kerning_table[(char1, char2)] = kerning_value + else: + break + except (struct.error, IndexError): + # Invalid data at 0x1000, no kerning + pass + + return bytes(length_table), kerning_table diff --git a/requirements.txt b/requirements.txt index 5816e26..c775b43 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -a816==1.1.0a1 +a816==1.1.0a2 pillow numpy diff --git a/src/battle/commands_patches.s b/src/battle/commands_patches.s index 20b9642..3494295 100644 --- a/src/battle/commands_patches.s +++ b/src/battle/commands_patches.s @@ -1,47 +1,60 @@ -command_length = 10 command_buffer_ptr = 0x97a6 + 0x601 ; old spell lists buffers -; move command cursor on the moved window -*=0x2b990 - lda.b #0x18 -{ -*=0x029CD6 - lda.b #command_length +.if BATTLE_CMD_VWF { + command_length = 6 + ; Command window + *=0x16fe5a + 6 * 2 + .db 0x05, 0x00 ,command_length + 2, 0x0d -*=0x029D15 - lda.b #command_length + *=0x2b990 + lda.b #0x18 +8 +} else { + command_length = 10 -*=0x029D42 - cpy.w #command_length + 2 + ; move command cursor on the moved window + *=0x2b990 + lda.b #0x18 + *=0x029CD6 + lda.b #command_length -*=0x029D5A - cpy.w #command_length + 2 + *=0x029D15 + lda.b #command_length -*=0x029D39 - lda.l assets_battle_commands_dat, x + *=0x029D42 + cpy.w #command_length + 2 -*=0x029CE0 - lda.b #command_length * 4 + *=0x029D5A + cpy.w #command_length + 2 -; patches source & length of battle commands used in display attack window. -*=0x02cb49 - lda.b #command_length + *=0x029D39 + lda.l assets_battle_commands_dat, x -*=0x02cb54 - lda.l assets_battle_commands_dat, x + *=0x029CE0 + lda.b #command_length * 4 + + ; patches source & length of battle commands used in display attack window. + *=0x02cb49 + lda.b #command_length + + ; attack window kick for example ends up there + *=0x02cb54 + lda.l assets_battle_commands_dat, x + + *=0x02cb5d + cpy.w #command_length + + ; Command window + *=0x16fe5a + 6 * 2 + .db 0x04, 0x00 ,command_length + 2, 0x0d -*=0x02cb5d - cpy.w #command_length -*=0x16FE54 - .db command_length * 2 - .db 0x0a - .dw command_buffer_ptr ; read address - .dw 0xC1F4 - 4 ; write address } + + { ; ram position of the prebuilt battle windows *=0x16FEAD +CmdTextBufPtrs: battle_data_size = command_length * 4 * 5 .dw command_buffer_ptr .dw command_buffer_ptr + battle_data_size @@ -49,12 +62,20 @@ battle_data_size = command_length * 4 * 5 .dw command_buffer_ptr + battle_data_size * 3 .dw command_buffer_ptr + battle_data_size * 4 +*=0x16FE54 + .db command_length * 2 + .db 0x0a + .dw command_buffer_ptr ; read address +.if BATTLE_CMD_VWF { + .dw 0xC1F4 - 2 ; write address +} else { + .dw 0xC1F4 - 4 ; write address +} + *=0x02999F ldx.w #battle_data_size -; Command window -*=0x16fe5a + 6 * 2 - .db 0x04, 0x00 ,command_length + 2, 0x0d } + diff --git a/src/battle/commands_reloc.s b/src/battle/commands_reloc.s new file mode 100644 index 0000000..e515419 --- /dev/null +++ b/src/battle/commands_reloc.s @@ -0,0 +1,150 @@ +Mult8_far := 0x2855c + +draw_command_list_for_character: +lda 0x1822 ; selected character slot + +sta 0x1816 +phx +jsr.w _draw_command_list_for_character +plx +rtl +_draw_command_list_for_character: +{ + stz.w 0x1817 + ldy #0x74FD ; keep the pointer in Y this will allow to run draw_single_command multiple times + ; to build {tile_flag}cmd1\n{tile_flag}cmd2\n{tile_flag}cmd3\n{tile_flag}cmd4\n{tile_flag}cmd5\0 + ; to issue a single draw text call to the command list region. + lda 0x1817 ; battle command slot + sta 0x26 + lda.b #command_length * 2 + sta 0x28 + jsr.l Mult8_far ; command_id * (command_length * 2) + + + lda 0x1817 ; slot ID + asl + asl + tax + stx 0x00 + + ;lda 0x1816 ; character id + ;asl + ;tax + + ;rep #0x20 + ;ldx.w #command_buffer_ptr - 10 + ;lda.l 0x16fead,x ;CmdTextBufPtrs,x + ;stx 0xef52 ; destination ptr ? + +_loop: + tdc + lda 0x1817 ; slot ID + asl + asl + tax + stx 0x00 + + lda 0x1816 ; character id + + rep #0x20 + asl + tax + lda.l 0x16feb7, x + clc + adc.b 0x00 + tax + sep #0x20 + + jsr.w draw_single_command + inc 0x1817 + lda 0x1817 + cmp #5 + beq _exit + lda #1 + sta.w 0x0000,y + iny + bra _loop +_exit: + + tdc + sta.w 0x0000,y + + sta 0xef55 + + ldx.w #command_buffer_ptr + stx 0xef52 ; destination + + rep #0x20 + +; Fill the window with 0x00ff before rendering + lda.w #command_length * 4 * 5 + sta 0x00 + +_clear_buffer_loop: + lda.w #0x00ff + sta.l 0x7e0000 + command_length * 4 * 5, x + dex + dex + dec 0 + bne _clear_buffer_loop + + sep #0x20 + + ldx #0x74fd ; text buffer + stx 0xef50 + lda.b #command_length ; draw text line length used for newline + sta 0xef54 + + jsr.l messages_vwf.init_commands_list + jsr.l _draw_text_battle_far + rts +} + +draw_single_command: +{ + tdc + sep #0x20 + lda.w 0x0001,x ; 0x3303 + + cmp #0xff + bne _continue + bra _exit +_continue: + asl + tax + tdc + lda.l assets_battle_commands_nul_ptr, x + tax + + lda #0x00 ; white text + and #0x80 + beq _active_command + lda #0x04 ; gray text + +_active_command: + sta.w 0x0001,y + lda #0x0e ; change tile flags + sta.w 0x0000,y + iny + iny + +_battle_command_loop: +{ +_loop: + lda.l assets_battle_commands_nul_dat,x + cmp #0 + beq _exit_command_loop + sta.w 0x0000,y + + inx + iny + bra _loop + +} +_exit_command_loop: +_pad_loop: + + +_exit: + rts +} \ No newline at end of file diff --git a/src/battle/message.s b/src/battle/message.s index a2fef41..76076b3 100644 --- a/src/battle/message.s +++ b/src/battle/message.s @@ -1,17 +1,169 @@ +.if 0 { +.scope vwf_tile_ring { +; Ring buffer for VWF tile allocation +; Each entry represents 8 consecutive tiles +; VWF system computes addresses from tile_id + +MAX_ENTRIES = 37 ; Number of 8-tile slots (296 tiles / 8 = 37) +TILES_PER_ENTRY = 8 ; Fixed 8 tiles per string + +; Memory layout +tile_ring_head = 0x703FF0 ; Current allocation position (entry index) - byte +tile_ring_count = 0x703FF1 ; Number of active allocations - byte +tile_ring_next_id = 0x703FF2 ; Next ID to assign - word +tile_ring_base_tile = 0x703FF4 ; Base tile ID for ring buffer area - byte + +; A: the base tile id +init: + ; tile_ring_base_tile should be set to your VWF tile area start + ; With 0x128 dynamic + 0x128 immortal = 0x250 (592) tiles total + ; But tile IDs are 1 byte (0-255), so max usable is 0xFF + ; Let's use dynamic area starting at tile 0x00 + + sta.w tile_ring_base_tile + + stz.b tile_ring_head + stz.b tile_ring_count + stz.w tile_ring_next_id + rts + +; Allocate next 8-tile slot +; Returns: A = starting tile_id (byte), X = allocation ID (word) +allocate_tiles: + ; Calculate tile_id: base_tile + (head * TILES_PER_ENTRY) + lda.w tile_ring_head + ; Multiply by 8 (shift left 3 times) + asl + asl + asl + ; Add to base + clc + adc.w tile_ring_base_tile + + ; Get current ID for tracking + ldx.w tile_ring_next_id + + rts + +; Commit the allocation (call after rendering to tiles) +; X = allocation ID +commit_allocation: +{ + ; Advance head pointer + lda.w tile_ring_head + inc + cmp.b #MAX_ENTRIES + bne _ok + lda.b #0 ; Wrap around +_ok: + sta.w tile_ring_head + + ; Increment count (max at MAX_ENTRIES) + lda.w tile_ring_count + cmp.b #MAX_ENTRIES + beq _next + inc + sta.w tile_ring_count +_next: + ; Increment next ID + inc.w tile_ring_next_id + + rts +} +; Get tile_id of a specific allocation by ID +; A = allocation ID (word) +; Returns: A = starting tile_id (byte), Carry = 0 if found, 1 if expired +get_tiles_by_id: +{ + ; Check if ID is still valid (within current range) + sec + lda.w tile_ring_next_id + sbc.w tile_ring_count + cmp.b 1,s ; Compare with requested ID on stack + bcs _not_found ; ID too old + + lda.w tile_ring_next_id + sec + sbc.b 1,s ; buffer_next_id - requested_id + cmp.w tile_ring_count + bcs _not_found ; ID too recent + + ; Calculate which entry index this ID maps to + lda.w tile_ring_head + sec + sbc.w tile_ring_count + clc + adc.b 1,s ; Add offset for this ID + + ; Handle wrap-around +_loop: + cmp.b #MAX_ENTRIES + bcc _ok + sec + sbc.b #MAX_ENTRIES + bra _loop +_ok: + ; Calculate tile_id + ; Multiply by 8 + asl + asl + asl + ; Add to base + clc + adc.w tile_ring_base_tile + + clc ; Found + rts + +_not_found: + sec ; Not found + rts +} +} +} + +; Currently works by region +; 0x00 -> 0x40 messages tiles +; 0x40 -> 0x80 monster names +; 0x80 -> 0xB0 char names +; 0xB0 -> 0xF0 commands ? this one is untested. + .scope battle_render { buffer_ptr = 0x703000 - buffer_size = 8*128*2 - + buffer_size = 8*(128+32)*2 + region_size = 48 + pending_transfer_mask = 0x703c00 bits_left_on_tile = 0xA9 tilemap_offset = bits_left_on_tile + 2 temp = bits_left_on_tile + 4 counter = bits_left_on_tile + 6 - current_char = bits_left_on_tile + 8 - + prev_char = bits_left_on_tile + 8 + current_char = prev_char + 1 font_ptr = assets_menu_font_dat - length_table_ptr = assets_menu_font_length_table_dat +init_monsters: + lda.b #region_size + bra __init +init_names: + lda.b #region_size * 2 + bra __init +init_commands_list: + lda.b #region_size * 3 +__init: + sta.l pending_transfer_mask + jsr.w render_allocator.init_with_tile_id + bra _internal_init init: +pha +lda #0 + + sta.l pending_transfer_mask +pla + jsr.w render_allocator.init +_internal_init: +.if ENABLE_KERNING_MENU { + stz.b prev_char +} jsr.w clear_buffer pha lda.b #0x08 @@ -21,13 +173,22 @@ init: stz.b temp stz.b counter - jsr.w render_allocator.init rts clear_buffer: pha phx - ldx.w #0 + phy + lda.l render_allocator.allocated_tile_id +rep #0x20 + asl + asl + asl + asl + tax + tdc +sep #0x20 + ldy.w #0 _clear_loop: lda.b #0xFF sta.l buffer_ptr, x @@ -35,8 +196,11 @@ _clear_loop: sta.l buffer_ptr + 1, x inx inx - cpx.w #buffer_size + 2 + iny + iny + cpy.w #region_size*16 bne _clear_loop + ply plx pla rts @@ -56,17 +220,20 @@ make_pointers: lda.b #0x00 xba rep #0x20 + pha asl asl asl - asl + adc 1,s tax - lda.w #0x0000 + pla + ;lda.w #0x0000 sep #0x20 - +_refresh_destination_pointer: lda.l render_allocator.allocated_tile_id rep #0x20 + and.w #0x00ff asl asl asl @@ -96,8 +263,14 @@ _display_char: jsr.w make_pointers + ; vwf8_lookup_kerning there: +.if ENABLE_KERNING_MENU { + pha + jsr.w _adjust_bits_left_for_kerning + pla +} rep #0x20 - lda.w #0x0010 + lda.w #0x0008 sta.b counter sep #0x20 @@ -121,8 +294,7 @@ _read_8x8_char: bra _store _shift: -DONT_USE_PPU_MULTIPLICATION = 1 ; PPU multiplication is being used by the NMI which wrecks char lines once in e while -.if DONT_USE_PPU_MULTIPLICATION { + ; PPU multiplication is being used by the NMI which wrecks char lines once in a while phx lda.l font_ptr, x xba @@ -167,55 +339,22 @@ _mul_1: _mul_0: sep #0x20 plx -} else { - ; expects bitsleft in A - phx - tax - lda.l vwf_shift_table, x - sta.l 0x004202 - - - plx - lda.l font_ptr, x - inx - sta.l 0x004203 ; MULTIPLICAND - - rep #0x20 - nop - nop - nop - nop - lda.l 0x004216 ; the result is stored in 0x4216-0x4217 - sep #0x20 -} -_and_store: - xba - phx - tyx - ora.l buffer_ptr, x - sta.l buffer_ptr, x - xba - ora.l buffer_ptr + 0x10, x - sta.l buffer_ptr + 0x10, x - txy - plx - iny - bra _next_line _store: xba phx tyx - ora.l buffer_ptr, x - sta.l buffer_ptr, x + ora.l buffer_ptr + 1, x + sta.l buffer_ptr + 1, x xba - ora.l buffer_ptr + 0x10, x - sta.l buffer_ptr + 0x10, x + ora.l buffer_ptr + 0x10 + 1, x + sta.l buffer_ptr + 0x10 + 1, x txy plx iny + iny _next_line: dec.b counter @@ -224,14 +363,11 @@ _next_line: rep #0x20 stz.b temp lda.w #0x0000 - ldx.w #0x0000 sep #0x20 - lda.b current_char - tax brk_bits_left: - lda.l length_table_ptr, x + lda.l font_ptr, x sta.b temp @@ -263,6 +399,223 @@ coupe: bra loopdec } +.if ENABLE_KERNING_MENU { +_adjust_bits_left_for_kerning: +{ + + lda.b bits_left_on_tile + sta.b temp + + jsr.w get_kerning_adjustment_linear_search + bcc _adjustment + bra _end +_adjustment: + pha + lda.b temp + clc + adc 1,s + cmp #0x9 + bcs __overflow + bra _no_overflow +__overflow: + pla + lda #0x08 + sta.b temp + pha + bra _no_adjustment +_no_overflow: + sta.b temp +_no_adjustment: + + pla +_end: + lda.b temp + sta.b bits_left_on_tile + +_overflow: + pha + lda.b current_char + sta.b prev_char + pla + rts +} + +get_kerning_adjustment_linear_search: +{ + phx + phy + rep #0x20 +; jsr.w _get_kerning_adjustment_binary_search + jsr.w _get_kerning_adjustment_linear_search + sep #0x20 + ply + plx + rts +} + +_get_kerning_adjustment_binary_search: +{ + phb + pea.w font_table >> 16 + plb + + kerning_table_offset = 256 * 9 + ldy.w #kerning_table_offset + lda.w font_ptr & 0xffff, y + beq not_found + dec + + ; Setup binary search bounds on stack + ; Stack layout (from top): [high] [low] [target_char] + pha ; Push high bound (count-1) + lda.w #0x0000 ; Low bound = 0 + pha ; Push low bound + lda.b prev_char ; Load target character + pha ; Push target for comparison + +_binary_loop: + ; Check if low > high (search finished) + lda 0x03, s ; Load low bound + cmp 0x05, s ; Compare with high bound + bcs not_found_cleanup ; If low >= high, not found + + ; Calculate mid = (low + high) / 2 + lda 0x03, s ; Load low + clc + adc 0x05, s ; Add high + lsr ; Divide by 2 + tax ; X = mid index + + ; Calculate address: mid * 3 + kerning_table_offset + 2 + ; (each entry is 3 bytes: 2 bytes char pair + 1 byte adjustment) + pha ; Save mid + asl ; mid * 2 + clc + adc 0x01, s ; Add original mid (now mid * 3) + clc + adc.w #kerning_table_offset + 2 + tay ; Y = address of entry + pla ; Restore mid to A + + ; Load char pair at this position + pha ; Save mid again + lda.w font_ptr & 0xffff, y ; Load 16-bit char pair + + ; Compare with target + cmp 0x03, s ; Compare with target_char + beq found_pair_cleanup ; Found exact match! + bcc search_upper_half ; If entry < target, search upper half + + ; Search lower half: high = mid - 1 + pla ; Get mid + dec ; mid - 1 + sta 0x05, s ; Update high bound + bra _binary_loop + +search_upper_half: + ; Search upper half: low = mid + 1 + pla ; Get mid + inc ; mid + 1 + sta 0x03, s ; Update low bound + bra _binary_loop + +found_pair_cleanup: + pla ; Remove mid from stack + + ; Calculate adjustment offset: Y + 2 (skip char pair) + iny + iny + lda.w font_ptr, y ; Load adjustment value (8-bit) - matches original + and.w #0x00ff ; Ensure high byte is clear + + ; Clean up stack + pla ; Remove target_char + pla ; Remove low bound + pla ; Remove high bound + + clc ; Clear carry (success) + plb + plb + rts + +not_found_cleanup: + ; Clean up stack + pla ; Remove target_char + pla ; Remove low bound + pla ; Remove high bound + +not_found: + lda.w #0x0000 + sec ; Set carry (not found) + plb + plb + rts + +found_pair: + ; This label kept for compatibility but shouldn't be reached + ; in binary search version + clc + plb + plb + rts +} + +_get_kerning_adjustment_linear_search: +{ + phb + pea.w font_table >> 16 + plb + + kerning_table_offset = 256 * 9 + ldy.w #kerning_table_offset + lda.w font_ptr & 0xffff, y + beq not_found + dec + tax + lda.w #0x0000 + +_loop: + txa + pha + asl + clc + adc 0x01, s + clc + adc.w #kerning_table_offset + 2 + + tay + pla + + lda.w font_ptr & 0xffff, y ; Load 16-bit char pair + cmp.b prev_char + beq found_pair ; Found exact match! + + txa + dec + tax + + bne _loop + +not_found: + lda.w #0x0000 + sec + plb + plb + rts + +found_pair: + iny + iny + lda.w font_ptr, y + and.w #0x00FF + clc + plb + plb + rts +} +} + + tilemap_write_no_inc: lda.l render_allocator.allocated_tile_id @@ -288,6 +641,7 @@ tilemap_write: inc.b tilemap_offset inc.b tilemap_offset sep #0x20 + tdc pla rts } @@ -327,11 +681,28 @@ tilemap_write: jsr.w battle_render.init rtl + init_commands_list: + jsr.l battle_flags.set_vwf_render + jsr.w battle_render.init_commands_list + rtl + init_monsters: + jsr.l battle_flags.set_vwf_render + jsr.w battle_render.init_monsters + rtl + + init_names: + jsr.l battle_flags.set_vwf_render + jsr.w battle_render.init_names + rtl + ; deinit the renderer ; disables messages renderer falling back to fixed mode. deinit: jsr.l battle_flags.clear_vwf_render ; vram transfer was moved to a trampoline in the battle nmi. + lda.l battle_render.pending_transfer_mask + ora #1 + sta.l battle_render.pending_transfer_mask rtl _wait_for_vblank: { @@ -343,9 +714,119 @@ tilemap_write: } DMA_TRANSFER: - dma_transfer_to_vram_call(battle_render.buffer_ptr, 0xb000>>1, battle_render.buffer_size, 0x1801) + pha + phx + phy + lda.l battle_render.pending_transfer_mask + bit #1 + beq _no_transfer + and #0xfe +.if SMART { + rep #0x20 + asl + asl + asl + asl + pha + clc + adc.w #0xb000 + lsr + tay + pla + clc + adc.w #battle_render.buffer_ptr + tax + sep #0x20 +} + ldy.w #0xb000 >> 1 + ldx.w #battle_render.buffer_ptr + phx + .if SMART{ + ldx.w #0x400 + } else { + ldx.w #0xc00 + } + stx 0x0e + plx + lda #0x70 + jsr.w _sram_dma_transfer_7 + lda #0x00 + sta.l battle_render.pending_transfer_mask +_no_transfer: + ply + plx + pla jsr.l 0x03fe03 rtl + +_sram_dma_transfer_7: + phb + pha + lda #0x00 + pha + plb + pla + sty 0x2116 + stx 0x4372 + sta 0x4374 + lda #0x01 + sta 0x4370 + lda #0x18 + sta 0x4371 + ldx.b 0x0e + stx 0x4375 + lda #1 << 7 + sta 0x420b + plb + rts + +new_line_escape_code_handler: + ; we might have something of interest in Y we might know where we are in the previous iteration ? + pha + ;jsr.w battle_render.tilemap_write + jsr.w render_allocator.increment + lda #8 + sta.b battle_render.bits_left_on_tile + pla + + lda.w 0xef54 + rep #0x20 + pha + asl + clc + adc 0x32 + sta 0x32 + sta.b render.tilemap_offset + + pla + clc + adc 0x32 + sta 0x34 + + + tdc + + tay + sep #0x20 + + rtl + +; escape code $01: newline +;02/A637: AD 54 EF LDA $EF54 +;02/A63A: C2 20 REP #$20 +;02/A63C: 48 PHA +;02/A63D: 0A ASL +;02/A63E: 18 CLC +;02/A63F: 65 32 ADC $32 +;02/A641: 85 32 STA $32 +;02/A643: 68 PLA +;02/A644: 18 CLC +;02/A645: 65 32 ADC $32 +;02/A647: 85 34 STA $34 +;02/A649: 7B TDC +;02/A64A: A8 TAY +;02/A64B: E2 20 SEP #$20 +;02/A64D: 60 RTS } diff --git a/src/battle/monsters_patches.s b/src/battle/monsters_patches.s new file mode 100644 index 0000000..2dac35f --- /dev/null +++ b/src/battle/monsters_patches.s @@ -0,0 +1,33 @@ +; transform the monster names loading routine from fixed size to pointed. +*=0x02a7d7 +{ +jsr.l load_monster_pointer +_loop: + lda.l assets_monsters_long_dat, x + beq _exit + jsr.w 0xA497 ; draw text + ;jsr.w msg_monster_window_trampoline + inx + bra _loop +_exit: + rts +_end: + .debug '{_end} < 0x02A7F0 ?' +} + + +*=0x02a7c2 + jsr.l initialize_monster_slot + rts + +; escape code 0x05 tab followed by a number of chars +*=0x02A6B3 + jsr.l tab_escape_code + nop + + ; dec 0 + nop + nop + ; bne a6b3 + nop + nop \ No newline at end of file diff --git a/src/battle/monsters_reloc.s b/src/battle/monsters_reloc.s new file mode 100644 index 0000000..f8f6634 --- /dev/null +++ b/src/battle/monsters_reloc.s @@ -0,0 +1,38 @@ +load_monster_pointer: + rep #0x20 + ;lda.w #127 - 3 + asl + tax + lda.l assets_monsters_long_ptr, x + tax + tdc + sep #0x20 + phy + jsr.w initialize_monster_slot_near + ply + rtl + +initialize_monster_slot: + jsr.w initialize_monster_slot_near + rtl +tab_escape_code: + jsr.w draw_spaces + rtl +initialize_monster_slot_near: + + ; clear monster slot with spaces + lda #11 + sta 0x00 +draw_spaces: + lda.b #0xff + sta (0x32), y + sta (0x34), y + iny + lda 0x36 + sta (0x32), y + sta (0x34), y + iny + dec 0x00 + bne draw_spaces + + rts diff --git a/src/battle/sram.i b/src/battle/sram.i index 440be63..81eb706 100644 --- a/src/battle/sram.i +++ b/src/battle/sram.i @@ -19,7 +19,7 @@ sram_base = 0x707000 ply } -BATTLE_FLAGS = 0x7FFFFF +BATTLE_FLAGS = 0x704F00 .macro battle_flags_set(value) { lda.b #value ora.l BATTLE_FLAGS @@ -42,7 +42,10 @@ BATTLE_FLAGS = 0x7FFFFF .macro battle_flag_switch(jump_table) { pha phx + lda #0 + xba lda.l BATTLE_FLAGS + asl tax lda.l jump_table, x diff --git a/src/battle/sram.s b/src/battle/sram.s index 7b39188..7157650 100644 --- a/src/battle/sram.s +++ b/src/battle/sram.s @@ -123,4 +123,35 @@ battle_flags_jump_table: sink: rtl +clear_names_window_buffer: + phx + phy + rep #0x20 + ldy.w #0 + ldx.w 0xef52 + _clear_name_loop: + lda.w #0x00ff + sta.l 0x7e0000, x + sta.l 0x7e0002, x + sta.l 0x7e0004, x + sta.l 0x7e0006, x + sta.l 0x7e0008, x + sta.l 0x7e000a, x + + txa + clc + adc.w #6 *2 + tax + iny + tya + cmp.w # 5 *2 + bne _clear_name_loop + + + sep #0x20 + ply + plx + tdc + sta 0x74FC, y + rtl \ No newline at end of file diff --git a/src/battle/sram_patches.s b/src/battle/sram_patches.s index f3193bc..eb6ab30 100644 --- a/src/battle/sram_patches.s +++ b/src/battle/sram_patches.s @@ -51,11 +51,56 @@ bcs 0x02A4AC *=0x02c99c + 4 .dw attack_names -;; monster names vwf try but being clear at every monster -;; needs a way to have immortal renders and temporary ones (used only for a few instants) -;*=0x02a409 -; jsr.w msg_window_draw_text_trampoline -; + + + + +; disable menu forced update every loop that might be too much +;*=0x028230 +; nop +; nop +; nop +.if BATTLE_MONSTERS_VWF { + ;; monster names vwf try but being clear at every monster + ;; needs a way to have immortal renders and temporary ones (used only for a few instants) + *=0x02a40d + jsr.w msg_monster_window_trampoline + + *=0x029486 + 12 + .dw 0x949a ; noop for monster names +} + + +.if BATTLE_NAMES_VWF { + ; this gets redrawn quite often + ; char names + *=0x02A29D + jsr.w msg_names_window_trampoline + ; wait frame runs a shite load of updates + *=0x029486 + 2 + .dw 0x949a ; noop for char names + + *=0x0296c0 + .dw 0x949a ; noop for periodic names update + + *=0x0296b0 + 16 + .dw 0x949a ; noop for periodic names update + + *=0x02A299 + jsr.l clear_names_window_buffer +} +; that's battle graphics 0xf that's a wait frame +;*=0x028517 +; nop +; nop +; nop +; nop + + +; disable periodic updates +;*=0x0296fa +; rts + ;; render attack names ;*=0x029d63 ; jsr.w msg_window_draw_text_trampoline @@ -64,20 +109,71 @@ bcs 0x02A4AC ;*=0x038229 ; jsr.l render_allocator.init_battle_far +.if BATTLE_NAMES_VWF + BATTLE_MONSTERS_VWF + BATTLE_CMD_VWF > 0 { + ;patches the newline control code handler to clear bitsleft on the current tile, allowing the monster string to be rendered. + *=0x02a637 + jsr.l messages_vwf.new_line_escape_code_handler + rts +} + + +.if BATTLE_CMD_VWF { + *=0x0296b0 + 2 + .dw 0x949a ; noop for periodic cmd window + + ;*=0x029CBF + ; jsr.l draw_command_list_for_character + ; rts + + ; nukes the draw all command list (pre renders all the windows) + *=0x029ca1 + rts + + ; always use the same buffer for all chars command list, + ; the buffer shall be updated if before the window is opened + ; due to those updates being quite costly now, we may want to avoid to re render too often + + *=0x0299f1 + pha + lda #0 + nop + + *=0x029989 + jsr.w draw_window_render_hook + +} + + *=0x02FFC2 -;sram_draw_text: -; jsr.l battle_flags.set_sram_copy -; jsr 0xA455 -; jsr.l battle_flags.clear_sram_copy -; rts +draw_window_render_hook: + jsr.w draw_command_list + ldx.w #0x0340 + rts +draw_command_list: + jsr.l draw_command_list_for_character + rts +msg_monster_window_trampoline: + jsr.l messages_vwf.init_monsters + bra _draw_text_battle +msg_names_window_trampoline: + jsr.l messages_vwf.init_names + bra _draw_text_battle msg_window_draw_text_trampoline: jsr.l messages_vwf.init +_draw_text_battle: jsr 0xA455 jsr.l messages_vwf.deinit rts +_draw_text_battle_far: + jsr.w _draw_text_battle + rtl attack_names: jsr.l messages_vwf.init jsr 0xcb32 jsr.l messages_vwf.deinit rts +{ +_end: +.debug '{_end} < 0x02FFFF ?' +} diff --git a/src/dialog.s b/src/dialog.s index 38db877..01af1f3 100644 --- a/src/dialog.s +++ b/src/dialog.s @@ -1,8 +1,4 @@ -dialog_ptr=0x20 - - - PointeurBank1de1: REP #0x20 LDA.L assets_bank1_1_ptr,X diff --git a/src/ingame/free_space.s b/src/ingame/free_space.s new file mode 100644 index 0000000..f61936c --- /dev/null +++ b/src/ingame/free_space.s @@ -0,0 +1,76 @@ +*=0x01ff40 +draw_window = 0x0180d9 +check_if_description_was_rendered: + pha + lda.l 0x004218 + ora.l 0x004219 + bne _not_still + pla + pha + + cmp.l render.last_drawn_text_ptr + bne _continue +_not_still: + pla + rts + _continue: + sta.l render.last_drawn_text_ptr + + pla + + pha + ldy.w #0xdcd6 + jmp _back + +draw_vwf_message: + jsr.l items_description.draw_trampoline + rts +draw_window_and_vwf_message: + + jsr.w draw_window + ; NOTE: quirks from the hardcore bank switching can be solved by loading the bank in A before the call. + pha + rep #0x20 + tya + adc.w #0x8000 + tay + sep #0x20 + pla + + iny + iny + iny + iny +draw_vwf_message_pos_with_bank: + lda.b #messages.use_on_whom >> 16 + +draw_vwf_message_pos: + jsr.l items_description.draw_trampoline_pos + rts + +.if 0 { +transform_window_trampoline: + jmp.l transform_window_far +} + +copy_text_with_dakuten: + jsr.l copy_text_with_dakuten_far + rts +.if DEBUG { +display_build_number: +{ + jsr.w 0x8301 ; draw text at position. + load_system_menu_text_pointer(newgame.build_number) + left = 1 + top = 27 + ldx.w #left * 2 + top * 64 + jsr.w 0x8798 ; copy text at position. + rts +} +} +{ + END_OF_FREE_SPACE: + .if END_OF_FREE_SPACE > 0x01ffff { + .debug '(Bank 0x01): End of free space was reached !' + } +} \ No newline at end of file diff --git a/src/ingame/items.s b/src/ingame/items.s index 59163da..2cfd0a5 100644 --- a/src/ingame/items.s +++ b/src/ingame/items.s @@ -94,52 +94,6 @@ __delta_r = 2 ldy.w #messages.cant_use_magic - 0x8000 jsr.w draw_window_and_vwf_message -; free space at the end of the bank - -*=0x01ff40 -draw_window = 0x0180d9 -check_if_description_was_rendered: - pha - - cmp.l render.last_drawn_text_ptr - bne _continue - pla - rts - _continue: - sta.l render.last_drawn_text_ptr - - pla - - pha - ldy.w #0xdcd6 - jmp _back - -draw_vwf_message: - jsr.l items_description.draw_trampoline - rts -draw_window_and_vwf_message: - jsr.w draw_window - ; NOTE: quirks from the hardcore bank switching can be solved by loading the bank in A before the call. - pha - rep #0x20 - tya - adc.w #0x8000 - tay - sep #0x20 - pla - - iny - iny - iny - iny -draw_vwf_message_pos_with_bank: - lda.b #messages.use_on_whom >> 16 - -draw_vwf_message_pos: - jsr.l items_description.draw_trampoline_pos - rts - - ; choice window *=0x01db40 load_system_menu_text_pointer(treasure.choice_window) diff --git a/src/ingame/magic.s b/src/ingame/magic.s index 90cd012..97f6855 100644 --- a/src/ingame/magic.s +++ b/src/ingame/magic.s @@ -32,15 +32,11 @@ first_column := 0x0248 - 4 ldy.w #spells.mp_needed & 0xffff jsr.w copy_text_with_dakuten -*=0x01ff80 -copy_text_with_dakuten: - jsr.l copy_text_with_dakuten_far - rts ; Grisement des types sorts : 'Blancs' 'Noirs' etc ... *=0x01B419 ldy.w #0x0007 - sta.w 0xC5FF,x + sta.w 0xC5FF + 2,x ; Spells type cursor offset *=0x01B0CE @@ -62,9 +58,6 @@ copy_text_with_dakuten: *=0x01dd6d menu_window(8, 0, 22, 26) -; [use spell] Magic name window. -*=0x01dd75 - menu_window(0, 0, 9, 7) ; [use spell] Use spell on whom window. *=0x01dd71 diff --git a/src/ingame/main.s b/src/ingame/main.s index 81e98e5..139bc8b 100644 --- a/src/ingame/main.s +++ b/src/ingame/main.s @@ -1,11 +1,18 @@ .include 'src/ingame/macros.i' + + { *=0x01DB61 - .dw 0x0000, 0x1A16 ; fenètre principale - .dw 0x05EE, 0x0307 ; fenètre Gils - .dw 0x04EE, 0x0207 ; fenetre temps - .dw 0x002E, 0x1107 ; fenètre menu principal - +.scope _main_menu { +characters_window: + menu_window(0, 0, 22, 26) +gil_window: + menu_window(22, 23, 8, 3) +time_window: + menu_window(23, 19, 7, 2) +menu: ; ptr 0xdb6d + menu_window(23, 0, 7, 17) +} *=0x01dd51 menu_window(1,8,29,17) @@ -76,7 +83,7 @@ end: *=0x0189b9 ; Level offset - adc.w #0x0044 + adc.w #0x0044 - 2 *=0x018a03 draw_hp_mp = 0x018a2a @@ -131,6 +138,17 @@ draw_hp_mp = 0x018a2a xba sta.w 0x0040, y +; translate can't fight text + +*=0x018B2A + load_system_menu_text_pointer(in_game_menu.cant_fight) + +; grey out more tiles for the first line in char block +*=0x018C30 + lda #15 + + + ;*=0x018b6b ; lda #0x42 @@ -280,37 +298,3 @@ rts ;018E50 60 RTS ; ---------------- - - -.if 0 { - ; Menu color palette I probably need to add one color - ; Palette 1, normal text - .db 0x00, 0x00 - .db 0x00, 0x40 - .db 0xCE, 0x39 - .db 0xFF, 0x7F - - ; Palette 2, greyed out text - .db 0x00, 0x00 - .db 0x00, 0x40 - .db 0x08, 0x21 - .db 0xEF, 0x3D - - ; Palette 3, yellow - .db 0x00, 0x00 - .db 0x00, 0x40 - .db 0x80, 0x02 - .db 0x7F, 0x03 - - ; Palette 4, red - .db 0x00, 0x00 - .db 0x00, 0x40 - .db 0xFF, 0x40 - .db 0x7F, 0x2E - - ; New Palette extra black to make shadows we'll probably add - .db 0x00, 0x00 - .db 0x00, 0x40 - .db 0x00, 0x00 - .db 0xFF, 0x7F -} \ No newline at end of file diff --git a/src/ingame/menus.i b/src/ingame/menus.i index c604c6c..0de0ca3 100644 --- a/src/ingame/menus.i +++ b/src/ingame/menus.i @@ -5,3 +5,5 @@ .include 'src/ingame/magic.s' .include 'src/ingame/shop.s' .include 'src/ingame/equip.s' +.include 'src/ingame/free_space.s' +.include 'src/ingame/windows.s' \ No newline at end of file diff --git a/src/ingame/options.s b/src/ingame/options.s index 9c8ebb0..9ff6e2e 100644 --- a/src/ingame/options.s +++ b/src/ingame/options.s @@ -20,15 +20,11 @@ *=0x01D1A4 load_system_menu_text_pointer(options.config) - ;jsr.w draw_window_and_vwf_message - ; move controls title window *=0x01E204 - .db 0x50 - .db 0x00 - .db 0x0B - .db 0x02 + menu_window(4, 0, 22, 2) + *=0x01D487 ldy.w #0xE204 diff --git a/src/ingame/shop.s b/src/ingame/shop.s index 7f95d51..f28293f 100644 --- a/src/ingame/shop.s +++ b/src/ingame/shop.s @@ -45,6 +45,19 @@ *=0x01C568 load_system_menu_text_pointer(shops.gils + 2) +*=0x01c74e + load_system_menu_text_pointer(shops.thank_you_window) + +*=0x01c962 + load_system_menu_text_pointer(shops.sell_window) + +*=0x01c41e + load_system_menu_text_pointer(shops.inventory_full) + +*=0x01c700 + load_system_menu_text_pointer(shops.not_enough_gils) + + ; Buy menu ; quantity hand pointer position "10" *=0x01cb12 diff --git a/src/ingame/windows.s b/src/ingame/windows.s new file mode 100644 index 0000000..90605a0 --- /dev/null +++ b/src/ingame/windows.s @@ -0,0 +1,68 @@ +; equip main window +*=0x01dda9 + menu_window(0, 0, 30, 11) + +; char 1 +*=0x01dd95 + menu_window(0, 0, 30, 11) +; char 2 +*=0x01dd99 + menu_window(0, 5, 30, 11) +; char 3 +*=0x01dd9d + menu_window(0, 10, 30, 11) +; char 4 +*=0x01dda1 + menu_window(0, 15, 30, 11) +; char 5 +*=0x01dda5 + menu_window(0, 20, 30, 11) + +; magic +;*=0x01B010 +; ldx.w #0xFF18 + 8 + +*=0x01dd55 + menu_window(1,0,19,7) + +*=0x01dd59 + menu_window(1,5,19,7) + +*=0x01dd5d + menu_window(1,10,19,7) + +*=0x01dd61 + menu_window(1,15,19,7) + +*=0x01dd65 + menu_window(1,20,19,7) + +; magic kind window +*=0x01dd69 + menu_window(23,2,7,7) + +; controls the amount of scroll to apply to bg4 to move the magic window kind window +*=0x01af90 +; 01/AF90: A9 34 LDA #$34 +; 01/AF92: 85 AD STA $AD + lda #0x68 + +; scroll out of the same window. +*=0x01b072 + lda #0x68 + +; status +*=0x01de01 + menu_window(0,1,29,24) + menu_window(18,6,12,4) + +; clear next line of text in the right menu +*=0x01a974 + ldy.w #0x270 + lda #7 + +; item title +*=0x01dcd2 + menu_window(22, 0, 7, 3) + + diff --git a/src/kerning.s b/src/kerning.s index 736e428..c925a16 100644 --- a/src/kerning.s +++ b/src/kerning.s @@ -15,10 +15,12 @@ _GetKerningAdjustmentLinearSearch: { ldy.w #0x1100 lda.b [font_addr], y ; right = NumKerningPairs + beq NotFound + dec tax lda.w #0x0000 _loop: - + txa pha asl clc @@ -37,8 +39,9 @@ _loop: dec tax - bne _loop + bpl _loop +NotFound: lda.w #0x0000 sec rts diff --git a/src/libmz.i b/src/libmz.i index 6d30664..bbe88b9 100644 --- a/src/libmz.i +++ b/src/libmz.i @@ -130,3 +130,11 @@ return_addr: rep #0x20 } +.macro fill_value(value, count) { + .for k := 0, count { + .dw value + } +} +.macro zero(count) { + fill_value(0, count) +} \ No newline at end of file diff --git a/src/menus/in_game_text.s b/src/menus/in_game_text.s index 434b01a..cc0e771 100644 --- a/src/menus/in_game_text.s +++ b/src/menus/in_game_text.s @@ -1,9 +1,12 @@ .include 'src/ingame/macros.i' .scope in_game_menu { +cant_fight: + .text 'KO' + .db 0 menu: ; window - .dw 0x002E, 0x1107 + menu_window(23, 0, 7, 17) ; position .dw 0x0070 .text 'Objets' @@ -40,12 +43,10 @@ time: } .scope items_menu { + items_menu_right: + menu_window(22, 0, 7, 3) item: - .db 2 - .db 0 - .db 7 - .db 3 - + menu_window(0, 0, 7, 3) .dw 0x0044 .text 'Objets' .db 0 @@ -58,23 +59,23 @@ time: .scope spells { white: - .dw 0x00EE + move_to(24, 3) .text 'Magie' .db 0 black: - .dw 0x016E + move_to(24, 5) .text 'Rituel' .db 0 summon: - .dw 0x01EE + move_to(24, 7) .text 'Chimere' .db 0 ninja: - .dw 0x016E + move_to(24, 5) .text 'Ninja ' .db 0 kokan: - .dw 0x0054 + move_to(24, 3) .text 'Echange' .db 0 mp_needed: @@ -236,8 +237,8 @@ config: controls: - .dw 0x0092 - .text 'Personaliser' + move_to(5, 1) + .text 'Contrôles Personalisés' .db 0x01 .dw 0x0204 diff --git a/src/menus/start_screen_text.s b/src/menus/start_screen_text.s index c03429d..4a63c15 100644 --- a/src/menus/start_screen_text.s +++ b/src/menus/start_screen_text.s @@ -6,6 +6,13 @@ new_game: .text 'Nouvelle partie' .db 0 +.if DEBUG { +build_number: + VERSION := 'v1.0.0a0' + .text '${BUILD_DATE} ${VERSION}' + .db 0 +} + time_load_save: .dw 0x046E + 2 .text 'Temps' @@ -45,6 +52,11 @@ saves: .text 'Sauvegardes' .db 0 +save_completed: + move_to(8, 11) + .text 'Sauvegarde terminée' + .db 0 + did_not_save: move_to(1, 1) .text 'Annulation ' ; extra space at the end to clear the previous title. diff --git a/src/menus/tools_shop_text.s b/src/menus/tools_shop_text.s index 3d19fc3..8fe3a3e 100644 --- a/src/menus/tools_shop_text.s +++ b/src/menus/tools_shop_text.s @@ -18,7 +18,7 @@ welcome_and_actions: quantity: .dw 0x0052 - .text 'Que désirez vous ?' + .text 'Que désirez vous ? ' .db 1 .dw 0x0144 .text 'Quantité' @@ -27,6 +27,49 @@ quantity: .text '1' .db 0 +thank_you_window: + menu_window(5,10,11,2) +thank_you_text: + move_to(6,11) + .text 'Merci !' + .db 0 + +inventory_full: + menu_window(1,10,20,4) + move_to(2,11) + .text 'L\'inventaire est' + .db 1 + move_to(2,13) + .text 'plein.' + .db 0 + +not_enough_gils: + menu_window(5,10,16,4) + move_to(6,11) + .text 'Vous n\'avez pas' + .db 1 + move_to(6,13) + .text 'de Gils.' + .db 0 + +sell_window: + menu_window(8,10,14,13) + move_to(13,13) + .text ' Unités' + .db 1 + move_to(19,15) + .text 'Gils' + .db 1 + move_to(10,17) + .text 'Êtes-vous' + .db 1 + move_to(11,19) + .text 'd\'accord ?' + .db 1 + move_to(12,21) + .text 'Oui Non' + .db 0 + weapons_title: .text 'Armes' .db 0 diff --git a/src/minimal_vwf_patches.s b/src/minimal_vwf_patches.s index 83052e0..ce04ab9 100644 --- a/src/minimal_vwf_patches.s +++ b/src/minimal_vwf_patches.s @@ -87,42 +87,69 @@ end_of_animation: { ; Oui -*=0x14F66C .table 'text/ff4_menus.tbl' - .text ' ' - .db 0x20 - .text ' ' - .db 0x20 - .text ' ' - .db 0x20 - -*=0x14F67C +*=0x14F656 + .dw 0x2016 + fill_value(0x2017, 5) + .dw 0x2018 + .dw 0x0000 + +*=0x14F666 + .dw 0x2019 + fill_value(0x20ff, 5) + .dw 0x201a + .dw 0x0000 + .dw 0x0000 + +*=0x14f676 + .dw 0x2019 + .dw 0x2014 .text 'O' .db 0x20 .text 'u' .db 0x20 .text 'i' .db 0x20 - + .dw 0x20ff + .dw 0x201a + .dw 0x0000 ; Non -*=0x14F68C - .text ' ' - .db 0x20 - .text ' ' - .db 0x20 - .text ' ' - .db 0x20 +*=0x14F686 + .dw 0x2019 + fill_value(0x20ff, 5) + .dw 0x201a + .dw 0x0000 + .dw 0x0000 -*=0x14F69C +*=0x14F696 + .dw 0x2019 + .dw 0x20ff .text 'N' .db 0x20 .text 'o' .db 0x20 .text 'n' .db 0x20 + .dw 0x20ff + .dw 0x201a + .dw 0x0000 +*=0x14F6A6 + .dw 0x201b + fill_value(0x201c, 5) + .dw 0x201d + .dw 0x0000 + fill_value(0x0000, 8) + + } +; yes/no cursor positions +; 0x28c4 0x2904 +*=0x00ae38 + ldx.w #0x28c4 - 1 +*=0x00ae51 + ldx.w #0x2904 - 1 ; Palette changes for allowing shadows *=0x15c229 @@ -143,3 +170,51 @@ end_of_animation: ;AE AA 16 LDX $16AA ;00823E 8E DD 0C STX $0CDD ;008241 20 13 8A JSR $8A13 + +; update the text palette used in the intro +*=0x8ff04 + .dw 0x0463 + + +*=0x00B363 + jsr.l wait_for_action_button + nop + nop + +; Make gils window bigger +gils_line_size = 0x18 +*=0x00ad28 + lda.b # gils_window_tilemap_1 >> 16 +;00/AD26: A9 14 LDA #$14 + +*=0x00ad2d + ldx.w #gils_window_tilemap_1 & 0xffff + +*=0x00ad4b + ldx.w #gils_window_tilemap_2 & 0xffff + + +*=0x00ad39 + ldx.w #gils_line_size + +*=0x00ad63 + ldx.w #gils_window_tilemap_3 +*=0x00ad69 + ldx.w #gils_line_size + +*=0x00ad51 + ldx.w #gils_line_size + +*=0x00ad7b + ldx.w #gils_window_tilemap_4 & 0xffff + +*=0x00ad81 + ldx.w #(gils_window_tilemap_4_end - gils_window_tilemap_4) & 0xffff + +; clear up longer gils window +*=0x00addd + ldx.w #0x100 + 0x80 + +; gils value vram position +*=0x00ad8a + ldx.w #0x28d3 + 2 diff --git a/src/new_game.s b/src/new_game.s index 81315f2..6694d57 100644 --- a/src/new_game.s +++ b/src/new_game.s @@ -43,6 +43,11 @@ *=0x019826 load_system_menu_text_pointer(newgame.load_this_save) +; for save menu we use the same string. +*=0x01981E + load_system_menu_text_pointer(newgame.load_this_save) + + *=0x01982C load_system_menu_text_pointer(newgame.yes_no) @@ -63,12 +68,16 @@ *=0x019AC5 load_system_menu_text_pointer(newgame.empty_save) - *=0x01cbad load_system_menu_text_pointer(newgame.saves) -*=0x1cc12 - load_system_menu_text_pointer(newgame.did_not_save) +*=0x01e050 + menu_window(7,10,19,2) + +*=0x1cc0d + load_system_menu_text_pointer(newgame.save_completed) +*=0x1cc12 + load_system_menu_text_pointer(newgame.did_not_save) } diff --git a/src/small_vwf/item_description.s b/src/small_vwf/item_description.s index e24f640..dc8ccb7 100644 --- a/src/small_vwf/item_description.s +++ b/src/small_vwf/item_description.s @@ -111,7 +111,9 @@ _reset_render: _transfer_item_description: - jsr.w wait_for_vblank - dma_transfer_to_vram_call(render.buffer_ptr, 0x5000>>1, render.buffer_size, 0x1801) + jsr.w wait_for_vblank + ; we could reduce the transfer size to the size of the string + dma_transfer_to_vram_call(render.buffer_ptr, 0x5000>>1, render.buffer_size, 0x1801) + ; use of the menu engine built in dma transfer in NMI rts } diff --git a/src/small_vwf/render.s b/src/small_vwf/render.s index b2097b5..c3453c4 100644 --- a/src/small_vwf/render.s +++ b/src/small_vwf/render.s @@ -106,6 +106,12 @@ _transfer_to_vram: .scope render_allocator { allocated_tile_id = 0x702F00 + +; tile_id in A +init_with_tile_id: + sta.l allocated_tile_id + rts + init: pha lda.b #0x00 @@ -136,11 +142,12 @@ get: .scope render { ; variables -__var_base = 0x00 +__var_base = 0x63 bits_left_on_tile = __var_base + 0x10 temp = bits_left_on_tile + 1 counter = temp + 1 -current_char = counter + 2 +prev_char = counter + 2 +current_char = prev_char + 1 tilemap_offset = 0x1d @@ -150,12 +157,14 @@ buffer_size = 0x300 last_drawn_text_ptr = buffer_ptr + buffer_size + 2 font_ptr = assets_menu_font_dat -length_table_ptr = assets_menu_font_length_table_dat init: ; Initialize the renderer ; clear a chunk of ram ; resets variables +.if ENABLE_KERNING_MENU { + stz.b prev_char +} initialize(bits_left_on_tile) jsr.w render_allocator.init pha @@ -204,11 +213,14 @@ make_pointers: lda.b #0x00 xba rep #0x20 + pha asl asl asl - asl + clc + adc 1, s tax + pla lda.w #0x0000 sep #0x20 @@ -234,7 +246,7 @@ display_char: jsr.w make_pointers rep #0x20 - lda.w #0x0010 + lda.w #0x0008 sta.b counter sep #0x20 @@ -242,7 +254,9 @@ char_line_loop: rep #0x20 lda.w #0x0000 sep #0x20 - +.if ENABLE_KERNING_MENU { + jsr.w _adjust_bits_left_for_kerning +} lda.b bits_left_on_tile cmp #0x08 @@ -255,6 +269,59 @@ _read_8x8_char: xba bra _store +_shift: + ; PPU multiplication is being used by the NMI which wrecks char lines once in a while + phx + lda.l font_ptr, x + ; bne _really_shift + ; inx + ; xba + ; bra _skip_empty_pixel_line +_really_shift: + xba + lda #0x00 + xba + + ; make jump_table_pointer + pha + lda.b bits_left_on_tile + asl + tax + pla + + rep #0x20 + jmp.w (_mul_table, x) +_mul_table: + .dw _mul_0 + .dw _mul_1 + .dw _mul_2 + .dw _mul_3 + .dw _mul_4 + .dw _mul_5 + .dw _mul_6 + .dw _mul_7 + .dw _mul_8 + +_mul_8: +_mul_7: + asl ; 1 +_mul_6: + asl ; 2 +_mul_5: + asl ; 3 +_mul_4: + asl ; 4 +_mul_3: + asl ; 5 +_mul_2: + asl ; 6 +_mul_1: + asl ; 7 +_mul_0: + sep #0x20 + plx + inx +.if 0 { _shift: ; expects bitsleft in A phx @@ -265,7 +332,11 @@ _shift: plx lda.l font_ptr, x - + bne _really_shift + inx + xba + bra _skip_empty_pixel_line +_really_shift: inx sta.l 0x004203 ; MULTIPLICAND @@ -277,35 +348,33 @@ _shift: nop lda.l 0x004216 ; the result is stored in 0x4216-0x4217 sep #0x20 - +} _store: xba phx tyx - ora.l buffer_ptr, x - sta.l buffer_ptr, x + ora.l buffer_ptr + 1, x + sta.l buffer_ptr + 1, x xba - ora.l buffer_ptr + 0x10, x - sta.l buffer_ptr + 0x10, x + ora.l buffer_ptr + 0x10 + 1, x + sta.l buffer_ptr + 0x10 + 1, x txy plx +_skip_empty_pixel_line: + iny iny - dec.b counter bne char_line_loop rep #0x20 stz.b temp lda.w #0x0000 - ldx.w #0x0000 sep #0x20 - lda.b current_char - tax brk_bits_left: - lda.l length_table_ptr, x + lda.l font_ptr, x sta.b temp @@ -348,6 +417,115 @@ coupe: sep #0x20 } +.if ENABLE_KERNING_MENU { +_adjust_bits_left_for_kerning: +{ + + lda.b bits_left_on_tile + cmp #8 + beq _overflow + sta.b temp + + jsr.w get_kerning_adjustment_linear_search + bcc _adjustment + bra _end +_adjustment: + pha + lda.b temp + clc + adc 1,s + sta.b temp +.if 0 { + bpl _no_adjustment + + and.b #0x80 + sta.b bits_left_on_tile + sta.b temp + lda.l render_allocator.allocated_tile_id + dec + sta.l render_allocator.allocated_tile_id + jsr.w _refresh_destination_pointer +} +_no_adjustment: + + pla +_end: + lda.b temp + sta.b bits_left_on_tile +_overflow: + pha + lda.b current_char + sta.b prev_char + pla + rts +} + +get_kerning_adjustment_linear_search: +{ + phx + phy + rep #0x20 + jsr.w _get_kerning_adjustment_linear_search + sep #0x20 + ply + plx + rts +} + +_get_kerning_adjustment_linear_search: +{ + phb + pea.w font_table >> 16 + plb + +kerning_table_offset = 256 * 9 + ldy.w #kerning_table_offset + lda.w font_ptr & 0xffff, y + beq not_found + dec + tax + lda.w #0x0000 + +_loop: + txa + pha + asl + clc + adc 0x01, s + clc + adc.w #kerning_table_offset + 2 + + tay + pla + + lda.w font_ptr & 0xffff, y ; Load 16-bit char pair + cmp.b prev_char + beq found_pair ; Found exact match! + + txa + dec + tax + + bne _loop + +not_found: + lda.w #0x0000 + sec + plb + plb + rts + +found_pair: + iny + iny + lda.w font_ptr, y + and.w #0x00FF + clc + plb + plb + rts +} +} tilemap_write_no_inc: _base_addr = 0x7e0000 lda.l render_allocator.allocated_tile_id diff --git a/src/vwf.s b/src/vwf.s index ef20f64..24a10a0 100644 --- a/src/vwf.s +++ b/src/vwf.s @@ -1,16 +1,95 @@ .include 'src/definitions.s' .include 'src/kerning.s' +wait_for_action_button: + jsr.w waitpad + rtl + +.if ENABLE_BUTTON_DISPLAY { +get_action_button_id: + lda.l 0x0016A9 + bne custom_mapping + lda.b #0x00 + xba + lda.b #0x00 + rts +custom_mapping: + lda.b #0x00 + xba + lda.l 0x001A37 ; action button id location + rts +} + +.macro make_color(r, g, b) { + red := (r >> 3) & 0b11111 + blue := (b >> 3) & 0xb11111 + green := (g >> 3) & 0xb11111 + + .dw (blue << 10) + (green << 5) + red +} + +.macro hex_color(color) { + make_color(color & 0xff, (color >> 8) & 0xff, (color >> 16)) +} + + +button_colors: +; 0 +; A Button + make_color(0xeb, 0x1a, 0x1d) + make_color(120, 10, 12) +; 1 +; B Button + make_color(0xfe, 0xce, 0x15) + make_color(136, 108, 0) +; 2 +; X Button + make_color(0x07, 0x49, 0xb4) + make_color(0, 53, 144) +; 3 +; Y Button + make_color(0x00, 0x8d, 0x45) + make_color(0, 70, 34) +; 4 +; Select Buttons + .dw 0b0011110111101111 + .dw 0b0001110011100111 + update_palette: -ldx.w 0x16AA -stx.w 0x0CDD -stx.w 0x0CE5 -rtl + ldx.w 0x16AA + stx.w 0x0CDD + stx.w 0x0CE5 +.if ENABLE_BUTTON_DISPLAY { + stx.w 0x0CED + ; black for the shadow but it could be a darker version of the color + ldx.w #0x0000 + stx.w 0x0CEF +pha + jsr.w get_action_button_id + + cmp #0x04 + bcc _proceed + ldx.w #5 +_proceed: + asl + asl + tax + + rep #0x20 + lda.l button_colors, x ; color + sta.w 0x0CF1 + lda.l button_colors + 2, x ; shadow color + sta.w 0x0CEF + sep #0x20 + lda #0x00 + xba +pla +} + rtl window_palette: -.if 1 { ; Menu color palette I probably need to add one color ; Palette 1, normal text .db 0x00, 0x00 @@ -35,7 +114,6 @@ window_palette: .db 0x00, 0x40 .db 0xFF, 0x40 .db 0x7F, 0x2E -} ;current_pos = 0x3d ;current_text_pointer = 0x0772 @@ -63,6 +141,7 @@ vwfinit: dma_transfer_to_vram_call(0x0AF000,0x6000, 0x800, 0x1801) jsr.w wait_for_vblank dma_transfer_to_vram_call(0x0AF000+0x800,0x6000+0x400, 0x800, 0x1801) + jsr.w wait_for_vblank ; Sets the BG3 vram pointer to 0x6000 lda 0x210C @@ -80,15 +159,16 @@ vwfstart: LDA.B #0x01 STA.W 0x420D - ; $04-$4F - var_base = 0x0 + ; 0x04-0x4F + var_base = 0x23 CNTR = var_base CURRENT_C = var_base + 2 BITSLEFT = var_base + 4 font_addr = var_base + 6 ; 7 8 - nchars = var_base + 9 - oldtilepos = var_base + 11 - TILEPOS = var_base + 13 + oldtilepos = var_base + 9 + TILEPOS = var_base + 11 + dialog_ptr = 0x20 + no_wait_for_action = 0xcb lda #0 @@ -139,6 +219,9 @@ parse: BNE _nxt1 lda #0x01 sta 0xDE +.if ENABLE_BUTTON_DISPLAY { + jsr.w draw_button +} JMP.W fin _nxt1: @@ -271,27 +354,29 @@ _loop_B5D2: ;**************** display_character_name: { + JSR.W ChargeLettreInc + xba + lda #0x00 + xba + ASL - STA.B 0x30 + pha ASL CLC - ADC 0x30 - STA.B 0x30 - STZ.B 0x31 - LDX.B 0x30 + ADC 1, s + tax + pla LDY.W #0x0000 - next: - LDX.B 0x30 lda #0x00 xba LDA 0x1500,X STA.B CURRENT_C CMP #0xFF BEQ exit - INX + PHX PHY JSR.W makeptr @@ -301,7 +386,7 @@ next: PLX suite: - INC.B 0x30 + inx INY CPY.W #0x0006 @@ -348,13 +433,16 @@ suit2: BRA end suit3: +; that's where new ends up - STZ.B CURRENT_C - STZ.B TILEPOS - +.if ENABLE_BUTTON_DISPLAY { + jsr.w draw_button +} LDA.B #0x08 - STA.B BITSLEFT + sta.b BITSLEFT + STZ.B CURRENT_C + STZ.B TILEPOS JSR.W clr JSR.W waitpad JSR.W wdisplay @@ -362,6 +450,46 @@ end: JMP.W main +draw_button: +{ + jsr.w get_action_button_id + cmp #4 ; select + bne _normal_button + lda #0xa5 + bra _store +_normal_button: + lda #0xa4 +_store: + sta.b CURRENT_C + jsr.w draw_ending_symbol + + rts +} + +draw_ending_symbol: + pha + + lda #0x08 + STA.B BITSLEFT + lda #0x4E + 24 + sta.b oldtilepos + + lda #0x4E + 25 + sta.b TILEPOS + + + + + ldx.w #0xa2 * 17 + ldy.w #0xcc0 + jsr.w makeptr + jsr.w ShiftNew + jsr.w wdisplay + + pla + rts + + ;************* ;** Musique ** ;************* @@ -570,7 +698,6 @@ TEXT_SHADOW :=1 eor.l WRAM + 2 + 0x20, x sta.l WRAM + 2 + 0x20, x pla - } TXY PLX @@ -585,7 +712,7 @@ TEXT_SHADOW :=1 REP #0x20 lda.b CURRENT_C -.if 0 { +.if ENABLE_KERNING { jsr.w GetKerningAdjustmentLinearSearch pha } else { @@ -737,18 +864,20 @@ transparent_bg_loop: } wait_key_up: - lda 0x02 + lda.l 0x000602 bne wait_key_up - lda 0x03 + lda.l 0x000603 bne wait_key_up rts wait_key_down: { - lda 0x02 + ACTION_BUTTON := 0x80 + lda.l 0x000602 + bit #ACTION_BUTTON ; Action button bne exit - lda 0x03 - beq wait_key_down + wai + bra wait_key_down exit: rts } @@ -769,7 +898,7 @@ waitpad: nowaitpad: - lda.b #0x20 + lda.b #0x30 { loop: jsr.w wait_for_vblank @@ -855,6 +984,10 @@ window: CMP #0xFF BEQ no_char_wait WAI ;wait for interrupts + lda.b no_wait_for_action ; add extra wait when in "story telling". + beq no_char_wait + jsr.w wait_for_vblank + jsr.w wait_for_vblank no_char_wait: } RTS @@ -862,14 +995,19 @@ window: winmap: .if TEXT_SHADOW { +.if ENABLE_BUTTON_DISPLAY { +last_character_palette := 2 +} else { +last_character_palette := 1 +} .dw 0x2000,0x2000,0x2019,0x2500,0x2502,0x2504,0x2506,0x2508,0x250A,0x250C,0x250E,0x2510,0x2512,0x2514,0x2516,0x2518,0x251A,0x251C,0x251E,0x2520,0x2522,0x2524,0x2526,0x2528,0x252A,0x252C,0x252E,0x2530,0x2532,0x201A,0x2000,0x2000 .dw 0x2000,0x2000,0x2019,0x2501,0x2503,0x2505,0x2507,0x2509,0x250B,0x250D,0x250F,0x2511,0x2513,0x2515,0x2517,0x2519,0x251B,0x251D,0x251F,0x2521,0x2523,0x2525,0x2527,0x2529,0x252B,0x252D,0x252F,0x2531,0x2533,0x201A,0x2000,0x2000 .dw 0x2000,0x2000,0x2019,0x2534,0x2536,0x2538,0x253A,0x253C,0x253E,0x2540,0x2542,0x2544,0x2546,0x2548,0x254A,0x254C,0x254E,0x2550,0x2552,0x2554,0x2556,0x2558,0x255A,0x255C,0x255E,0x2560,0x2562,0x2564,0x2566,0x201A,0x2000,0x2000 .dw 0x2000,0x2000,0x2019,0x2535,0x2537,0x2539,0x253B,0x253D,0x253F,0x2541,0x2543,0x2545,0x2547,0x2549,0x254B,0x254D,0x254F,0x2551,0x2553,0x2555,0x2557,0x2559,0x255B,0x255D,0x255F,0x2561,0x2563,0x2565,0x2567,0x201A,0x2000,0x2000 .dw 0x2000,0x2000,0x2019,0x2568,0x256A,0x256C,0x256E,0x2570,0x2572,0x2574,0x2576,0x2578,0x257A,0x257C,0x257E,0x2580,0x2582,0x2584,0x2586,0x2588,0x258A,0x258C,0x258E,0x2590,0x2592,0x2594,0x2596,0x2598,0x259A,0x201A,0x2000,0x2000 .dw 0x2000,0x2000,0x2019,0x2569,0x256B,0x256D,0x256F,0x2571,0x2573,0x2575,0x2577,0x2579,0x257B,0x257D,0x257F,0x2581,0x2583,0x2585,0x2587,0x2589,0x258B,0x258D,0x258F,0x2591,0x2593,0x2595,0x2597,0x2599,0x259B,0x201A,0x2000,0x2000 -.dw 0x2000,0x2000,0x2019,0x259C,0x259E,0x25A0,0x25A2,0x25A4,0x25A6,0x25A8,0x25AA,0x25AC,0x25AE,0x25B0,0x25B2,0x25B4,0x25B6,0x25B8,0x25BA,0x25BC,0x25BE,0x25C0,0x25C2,0x25C4,0x25C6,0x25C8,0x25CA,0x25CC,0x25CE,0x201A,0x2000,0x2000 -.dw 0x2000,0x2000,0x2019,0x259D,0x259F,0x25A1,0x25A3,0x25A5,0x25A7,0x25A9,0x25AB,0x25AD,0x25AF,0x25B1,0x25B3,0x25B5,0x25B7,0x25B9,0x25BB,0x25BD,0x25BF,0x25C1,0x25C3,0x25C5,0x25C7,0x25C9,0x25CB,0x25CD,0x25CF,0x201A,0x2000,0x2000 +.dw 0x2000,0x2000,0x2019,0x259C,0x259E,0x25A0,0x25A2,0x25A4,0x25A6,0x25A8,0x25AA,0x25AC,0x25AE,0x25B0,0x25B2,0x25B4,0x25B6,0x25B8,0x25BA,0x25BC,0x25BE,0x25C0,0x25C2,0x25C4,0x25C6,0x25C8,0x25CA,0x25CC,(0x21CE + (last_character_palette << 10)),0x201A,0x2000,0x2000 +.dw 0x2000,0x2000,0x2019,0x259D,0x259F,0x25A1,0x25A3,0x25A5,0x25A7,0x25A9,0x25AB,0x25AD,0x25AF,0x25B1,0x25B3,0x25B5,0x25B7,0x25B9,0x25BB,0x25BD,0x25BF,0x25C1,0x25C3,0x25C5,0x25C7,0x25C9,0x25CB,0x25CD,(0x21CF + (last_character_palette << 10)),0x201A,0x2000,0x2000 } else { .dw 0x2000,0x2000,0x2019,0x2100,0x2102,0x2104,0x2106,0x2108,0x210A,0x210C,0x210E,0x2110,0x2112,0x2114,0x2116,0x2118,0x211A,0x211C,0x211E,0x2120,0x2122,0x2124,0x2126,0x2128,0x212A,0x212C,0x212E,0x2130,0x2132,0x201A,0x2000,0x2000 .dw 0x2000,0x2000,0x2019,0x2101,0x2103,0x2105,0x2107,0x2109,0x210B,0x210D,0x210F,0x2111,0x2113,0x2115,0x2117,0x2119,0x211B,0x211D,0x211F,0x2121,0x2123,0x2125,0x2127,0x2129,0x212B,0x212D,0x212F,0x2131,0x2133,0x201A,0x2000,0x2000 @@ -889,13 +1027,59 @@ intromap: .dw 0x2000,0x2000,0x2000,0x2135,0x2137,0x2139,0x213B,0x213D,0x213F,0x2141,0x2143,0x2145,0x2147,0x2149,0x214B,0x214D,0x214F,0x2151,0x2153,0x2155,0x2157,0x2159,0x215B,0x215D,0x215F,0x2161,0x2163,0x2165,0x2167,0x2000,0x2000,0x2000 .dw 0x2000,0x2000,0x2000,0x2168,0x216A,0x216C,0x216E,0x2170,0x2172,0x2174,0x2176,0x2178,0x217A,0x217C,0x217E,0x2180,0x2182,0x2184,0x2186,0x2188,0x218A,0x218C,0x218E,0x2190,0x2192,0x2194,0x2196,0x2198,0x219A,0x2000,0x2000,0x2000 .dw 0x2000,0x2000,0x2000,0x2169,0x216B,0x216D,0x216F,0x2171,0x2173,0x2175,0x2177,0x2179,0x217B,0x217D,0x217F,0x2181,0x2183,0x2185,0x2187,0x2189,0x218B,0x218D,0x218F,0x2191,0x2193,0x2195,0x2197,0x2199,0x219B,0x2000,0x2000,0x2000 -.dw 0x2000,0x2000,0x2000,0x219C,0x219E,0x21A0,0x21A2,0x21A4,0x21A6,0x21A8,0x21AA,0x21AC,0x21AE,0x21B0,0x21B2,0x21B4,0x21B6,0x21B8,0x21BA,0x21BC,0x21BE,0x21C0,0x21C2,0x21C4,0x21C6,0x21C8,0x21CA,0x21CD,0x21CF,0x2000,0x2000,0x2000 -.dw 0x2000,0x2000,0x2000,0x219D,0x219F,0x21A1,0x21A3,0x21A5,0x21A7,0x21A9,0x21AB,0x21AD,0x21AF,0x21B1,0x21B3,0x21B5,0x21B7,0x21B9,0x21BB,0x21BD,0x21BF,0x21C1,0x21C3,0x21C5,0x21C7,0x21C9,0x21CB,0x21CE,0x21D0,0x2000,0x2000,0x2000 +.dw 0x2000,0x2000,0x2000,0x219C,0x219E,0x21A0,0x21A2,0x21A4,0x21A6,0x21A8,0x21AA,0x21AC,0x21AE,0x21B0,0x21B2,0x21B4,0x21B6,0x21B8,0x21BA,0x21BC,0x21BE,0x21C0,0x21C2,0x21C4,0x21C6,0x21C8,0x21CA,0x21CC,0x21CE,0x2000,0x2000,0x2000 +.dw 0x2000,0x2000,0x2000,0x219D,0x219F,0x21A1,0x21A3,0x21A5,0x21A7,0x21A9,0x21AB,0x21AD,0x21AF,0x21B1,0x21B3,0x21B5,0x21B7,0x21B9,0x21BB,0x21BD,0x21BF,0x21C1,0x21C3,0x21C5,0x21C7,0x21C9,0x21CB,0x21CD,0x21CF,0x2000,0x2000,0x2000 endintromap: +gils_window_size := 10 +gils_window_tilemap_1: + .dw 0, 0 + .db 0x16,0x20 + fill_value(0x2017, gils_window_size - 2) + .db 0x18,0x20 + +gils_window_tilemap_2: + .dw 0, 0 + + .db 0x19,0x20 + fill_value(0x20ff, gils_window_size - 2) + .db 0x1a,0x20 + +gils_window_tilemap_3: + .dw 0, 0 + + .db 0x19,0x20 + fill_value(0x20ff, gils_window_size - 2) + .db 0x1a,0x20 + +gils_window_tilemap_4: + .dw 0, 0 + + .db 0x19,0x20 + fill_value(0x20ff, gils_window_size - 2) + .db 0x1a,0x20 + + fill_value(0x0000, 0x16) + + .db 0x19,0x20 + fill_value(0x20ff, gils_window_size - 2 - 4) + .text 'G' + .db 0x20 + .text 'i' + .db 0x20 + .text 'l' + .db 0x20 + .text 's' + .db 0x20 + .db 0x1a,0x20 ; "gil" + fill_value(0x0000, 0x16) + .db 0x1b,0x20 + fill_value(0x201c, gils_window_size - 2) + .db 0x1d,0x20 +gils_window_tilemap_4_end: diff --git a/tests/test_font_converter.py b/tests/test_font_converter.py new file mode 100644 index 0000000..2e2c762 --- /dev/null +++ b/tests/test_font_converter.py @@ -0,0 +1,352 @@ +from script import Table +from pathlib import Path +import numpy as np +import pytest +from PIL import Image +import tempfile +import os + +from numpy.f2py.auxfuncs import ischaracter + +from utils.font_converter import FontConverter + + +class TestFontConverter: + + @pytest.fixture + def sample_font_file(self): + data = np.zeros((32, 32), dtype=np.uint8) + data[0:8, 0:8] = 1 + data[0:8, 9:17] = 1 + + with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as f: + Image.fromarray(data * 255).save(f.name, 'PNG') + yield f.name + os.unlink(f.name) + + + + def test_font_converter_init(self, sample_font_file): + converter = FontConverter(sample_font_file) + assert converter.font_file == sample_font_file + assert converter.image is None + + def test_load_image(self, sample_font_file): + converter = FontConverter(sample_font_file) + converter._load_image() + assert converter.image is not None + assert isinstance(converter.image, np.ndarray) + + def test_get_char_with_grid(self, sample_font_file): + converter = FontConverter(sample_font_file) + char = converter.get_char(0, True, 8, 8) + assert char.shape == (8, 8) + + def test_get_char_without_grid(self, sample_font_file): + converter = FontConverter(sample_font_file) + char = converter.get_char(0, False, 8, 8) + assert char.shape == (8, 8) + + def test_char_as_1bbp(self, sample_font_file): + converter = FontConverter(sample_font_file) + char = np.array([[1, 0, 1, 0, 1, 0, 1, 0]]) + result = converter.char_as_1bbp(char) + assert isinstance(result, bytes) + assert len(result) == 1 + assert result[0] == 0b10101010 + + def test_get_max_width(self, sample_font_file): + converter = FontConverter(sample_font_file) + char = np.array([[1, 1, 0, 0], [1, 1, 1, 0]]) + width = converter.get_max_width(char) + assert width == 3 + + def test_convert_to_1bpp(self, sample_font_file): + converter = FontConverter(sample_font_file) + len_table, data = converter.convert_to_1bpp(has_grid=True, char_height=8) + assert isinstance(len_table, dict) + assert isinstance(data, bytes) + + def test_convert_to_2bpp(self, sample_font_file): + converter = FontConverter(sample_font_file) + len_table, data = converter.convert_to_2bpp(has_grid=True, char_height=8) + assert isinstance(len_table, dict) + assert isinstance(data, bytes) + + def test_write_as_2bpp(self, sample_font_file): + converter = FontConverter(sample_font_file) + data = np.zeros((8, 16), dtype=np.uint8) + result = converter.write_as_2bpp(data) + assert isinstance(result, bytearray) + + def test_remove_grid(self, sample_font_file): + converter = FontConverter(sample_font_file) + with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as f: + converter.remove_grid(f.name) + assert os.path.exists(f.name) + os.unlink(f.name) + + def test_with_vwf_font_and_tbl(self): + from script import Table + from pathlib import Path + + test_dir = Path(__file__).parent.parent + vwf_path = test_dir / "fonts" / "vwf.png" + tbl_path = test_dir / "text" / "ff4fr.tbl" + + if not vwf_path.exists() or not tbl_path.exists(): + pytest.skip("VWF font or TBL file not found") + + # Load the table to find char index for 'T' + table = Table(str(tbl_path)) + char_bytes = table.to_bytes("T") + + if not char_bytes: + pytest.skip("Character 'T' not found in TBL file") + + char_index = char_bytes[0] # Get the first byte as char index + + # Test FontConverter with actual VWF font + converter = FontConverter(str(vwf_path)) + char_data = converter.get_char(char_index, False, 8, 16) + + assert char_data.shape == (16, 8) + assert isinstance(char_data, np.ndarray) + + # Test that the character has some non-zero pixels (assuming 'T' has content) + assert np.any(char_data > 0), "Character 'T' should have some visible pixels" + + # Get the width of the character and trim to that width + char_width = converter.get_max_width(char_data) + trimmed_char = char_data[:, :char_width] + + assert trimmed_char.shape == (16, char_width) + assert char_width > 0, "Character 'T' should have a positive width" + + # Test with character "a" + char_a_bytes = table.to_bytes("a") + char_a_index = char_a_bytes[0] + char_a_data = converter.get_char(char_a_index, False, 8, 16) + + assert char_a_data.shape == (16, 8) + assert np.any(char_a_data > 0), "Character 'a' should have some visible pixels" + + # Get the width of character "a" and trim to that width + char_a_width = converter.get_max_width(char_a_data) + trimmed_char_a = char_a_data[:, :char_a_width] + + # Find where 'a' actually starts horizontally (first non-empty column) + a_cols_with_pixels = np.any(trimmed_char_a > 0, axis=0) + a_left_col = np.argmax(a_cols_with_pixels) if np.any(a_cols_with_pixels) else 0 + a_right_col = len(a_cols_with_pixels) - 1 - np.argmax(a_cols_with_pixels[::-1]) if np.any( + a_cols_with_pixels) else char_a_width - 1 + a_actual_width = a_right_col - a_left_col + 1 + + # Extract only the part of 'a' that has pixels + actual_trimmed_char_a = trimmed_char_a[:, a_left_col:a_right_col + 1] + + assert trimmed_char_a.shape == (16, char_a_width) + assert char_a_width > 0, "Character 'a' should have a positive width" + + # Find the vertical extent of 'a' - where it actually has pixels + a_rows_with_pixels = np.any(trimmed_char_a > 0, axis=1) + a_top_row = np.argmax(a_rows_with_pixels) if np.any(a_rows_with_pixels) else 0 + a_bottom_row = len(a_rows_with_pixels) - 1 - np.argmax(a_rows_with_pixels[::-1]) if np.any( + a_rows_with_pixels) else 15 + a_height = a_bottom_row - a_top_row + 1 + + # Find the vertical extent of 'T' + t_rows_with_pixels = np.any(trimmed_char > 0, axis=1) + t_top_row = np.argmax(t_rows_with_pixels) if np.any(t_rows_with_pixels) else 0 + t_bottom_row = len(t_rows_with_pixels) - 1 - np.argmax(t_rows_with_pixels[::-1]) if np.any( + t_rows_with_pixels) else 15 + + # Compute horizontal kerning (1 pixel spacing between chars) + kerning = 1 + + # Create a combined array with T + kerning + a + combined_width = char_width + kerning + char_a_width + combined_char = np.zeros((16, combined_width), dtype=np.uint8) + + # Place T at the beginning + combined_char[:, :char_width] = trimmed_char + + # Place a after T with kerning + combined_char[:, char_width + kerning:] = trimmed_char_a + + assert combined_char.shape == (16, combined_width) + assert np.any(combined_char[:, :char_width] > 0), "T part should have visible pixels" + assert np.any(combined_char[:, char_width + kerning:] > 0), "a part should have visible pixels" + + # Verify kerning space is empty + if kerning > 0: + assert not np.any(combined_char[:, char_width:char_width + kerning] > 0), "Kerning space should be empty" + + # Compute optimal kerning by finding how much closer we can bring 'a' to 'T' + # Since T has horizontal crossbar at top and 'a' sits lower, they can overlap significantly + max_kerning_reduction = 0 + + # Check each possible kerning reduction, allowing 'a' to move under T's crossbar + for reduction in range(1, kerning + char_width + 1): # Can potentially overlap completely + collision = False + + # Calculate where 'a' would start with this reduction + a_start_pos = char_width + kerning - reduction + + # Check for pixel collision only in rows where both characters have content + overlap_top = max(a_top_row, t_top_row) + overlap_bottom = min(a_bottom_row, t_bottom_row) + + # Only check for collision if there's actual vertical overlap + if overlap_top <= overlap_bottom: + for row in range(overlap_top, overlap_bottom + 1): + for a_col in range(char_a_width): + a_pixel_pos = a_start_pos + a_col + + # If 'a' pixel is within T's width, check for collision + if 0 <= a_pixel_pos < char_width: + t_pixel = trimmed_char[row, a_pixel_pos] + a_pixel = trimmed_char_a[row, a_col] + + if t_pixel > 0 and a_pixel > 0: + collision = True + break + if collision: + break + + if not collision: + max_kerning_reduction = reduction + else: + break + + optimal_kerning = kerning - max_kerning_reduction + 1 + + # Debug: print the kerning values to see what's happening + print(f"Original kerning: {kerning}") + print(f"Max kerning reduction: {max_kerning_reduction}") + print(f"Optimal kerning: {optimal_kerning}") + print(f"T vertical range: {t_top_row}-{t_bottom_row}") + print(f"a vertical range: {a_top_row}-{a_bottom_row}") + + # Create optimally kerned version using actual character dimensions + optimal_combined_width = char_width + optimal_kerning + a_actual_width + optimal_combined_char = np.zeros((16, optimal_combined_width), dtype=np.uint8) + + # Place T at the beginning + optimal_combined_char[:, :char_width] = trimmed_char + + # Place a with optimal kerning at its correct vertical position + a_start_col = char_width + optimal_kerning + a_end_col = a_start_col + a_actual_width + + print(f"T ends at column: {char_width - 1}") + print(f"a starts at column: {a_start_col}") + print(f"Gap between T and a: {a_start_col - char_width} pixels") + print(f"a_actual_width: {a_actual_width}") + print(f"actual_trimmed_char_a shape: {actual_trimmed_char_a.shape}") + print(f"a_end_col: {a_end_col}") + print(f"Placing 'a' from column {a_start_col} to {a_end_col - 1}") + print(f"a_left_col: {a_left_col}") + print(f"a_right_col: {a_right_col}") + print(f"First row of 'a' that has pixels: {actual_trimmed_char_a[a_top_row, :].tolist()}") + + # Only place 'a' pixels in the rows where 'a' actually has content + optimal_combined_char[a_top_row:a_bottom_row + 1, a_start_col:a_start_col + char_a_width] = trimmed_char_a[ + a_top_row:a_bottom_row + 1, :] + + assert optimal_combined_char.shape == (16, optimal_combined_width) + assert optimal_combined_width <= combined_width, "Optimal kerning should not increase width" + + kerning_improvement = combined_width - optimal_combined_width + assert kerning_improvement >= 0, "Kerning should improve or stay the same" + + def test_render_string_methods(self): + + known_pairs_to_kern = [] + + letters = ["T", "V", "F"] + vowels = ["a", "e", "i", "o", "u", "é", "à", "è", "ê", "ï"] + for letter in letters: + for vowel in vowels: + known_pairs_to_kern.append(letter + vowel) + + for vowel in vowels: + known_pairs_to_kern.append(vowel + "j") + + test_dir = Path(__file__).parent.parent + vwf_path = test_dir / "fonts" / "vwf.png" + tbl_path = test_dir / "text" / "ff4fr.tbl" + + # Create converter and table + converter = FontConverter(str(vwf_path), has_grid=False, char_height=16) + + table = Table(str(tbl_path)) + pairs_to_kern_for_real = [] + # known_pairs_to_kern = [] + # symbols = set(filter(lambda k: len(k) == 1 and k.isalpha(), table.lookup.keys())) + # + # symbols = symbols - {'\n'} + # for k in symbols: + # for j in symbols: + # known_pairs_to_kern .append(k+j) + for pair in known_pairs_to_kern: + chars = table.to_bytes(pair) + if len(chars) != 2: + continue + if converter.compute_kerning(chars[0], chars[1]) < 1: + pairs_to_kern_for_real.append(pair) + + # test_dir = Path(__file__).parent.parent + # vwf_path = test_dir / "fonts" / "8x8vwf2p.png" + # tbl_path = test_dir / "text" / "ff4_menus.tbl" + # # Create converter and table + # converter = FontConverter(str(vwf_path), has_grid=True, char_height=8) + # + + # Test string + test_text = "-".join(pairs_to_kern_for_real) + text_bytes = table.to_bytes(test_text) + + if not text_bytes: + pytest.skip(f"Could not convert text '{test_text}' to bytes") + + # Test simple render_string method + simple_rendered = converter.render_string(text_bytes) + + # assert simple_rendered.shape[0] == 16, "Rendered text should have correct height" + # assert simple_rendered.shape[1] > 0, "Rendered text should have positive width" + # assert np.any(simple_rendered > 0), "Rendered text should have visible pixels" + # + # Test optimized render_kerned_string method + kerned_rendered = converter.render_kerned_string(text_bytes) + + # assert kerned_rendered.shape[0] == 16, "Kerned text should have correct height" + # assert kerned_rendered.shape[1] > 0, "Kerned text should have positive width" + # assert np.any(kerned_rendered > 0), "Kerned text should have visible pixels" + # + # Kerned version should generally be more compact (smaller width) + # though this isn't guaranteed for all strings + print(f"Simple rendering width: {simple_rendered.shape[1]}") + print(f"Kerned rendering width: {kerned_rendered.shape[1]}") + print(f"Space saved: {simple_rendered.shape[1] - kerned_rendered.shape[1]} pixels") + kerned_rendered = kerned_rendered * 255 + simple_rendered = simple_rendered * 255 + # Both should have the same height + assert simple_rendered.shape[0] == kerned_rendered.shape[0], "Both renderings should have same height" + + def test_kerning_pair(self) -> None: + test_dir = Path(__file__).parent.parent + vwf_path = test_dir / "fonts" / "vwf.png" + tbl_path = test_dir / "text" / "ff4fr.tbl" + + # Create converter and table + converter = FontConverter(str(vwf_path), has_grid=False, char_height=16) + + table = Table(str(tbl_path)) + + data = table.to_bytes("fo") + advance_x = converter.compute_kerning(data[0], data[1], 0) + + kerned_rendered = converter.render_kerned_string(data) * 255 + + assert advance_x != 0 diff --git a/test_format_bank.py b/tests/test_format_bank.py similarity index 78% rename from test_format_bank.py rename to tests/test_format_bank.py index cb3d49b..f75013d 100644 --- a/test_format_bank.py +++ b/tests/test_format_bank.py @@ -1,11 +1,6 @@ from format_bank_xml import process_dialogue -def test_split_sentences() -> None: - # This test is no longer needed since we use lexer/parser approach - pass - - def test_format() -> None: """Test that a [new]\n tag is inserted between character speches, \n should be inserted after a punctuation if it's not the end of the speach @@ -22,11 +17,11 @@ def test_format() -> None: assert ( formatted - == """Edge: And here I am all pumped up + == """[bold]Edge[normal]: And here I am all pumped up to fight that bastard! Ah, well... can't be breaking a sweat in front of the ladies.[new] -Golbeze: Cecil...[end]""" +[bold]Golbez[normal]: Cecil...[end]""" ) @@ -48,12 +43,12 @@ def test_format2() -> None: assert ( formatted - == """Soldier: Yes sir![new] -Soldier: The monsters have been + == """[bold]Soldier[normal]: Yes sir![new] +[bold]Soldier[normal]: The monsters have been increasing lately though...[new] -Soldier: There's just too many of them -nowadays.[new] -Cecil: Is something... happening?[end]""" +[bold]Soldier[normal]: There's just too many of +them nowadays.[new] +[bold]Cecil[normal]: Is something... happening?[end]""" ) @@ -66,19 +61,19 @@ def test_format3() -> None: assert ( formatted - == """Soldier: Agh![new] -Cecil: Are you all right?[new] -Soldier: There's more of them![new] -Cecil: Damn![end]""" + == """[bold]Soldier[normal]: Agh![new] +[bold]Cecil[normal]: Are you all right?[new] +[bold]Soldier[normal]: There's more of them![new] +[bold]Cecil[normal]: Damn![end]""" ) def test_formatting_idempotency() -> None: - first_formatting = process_dialogue("""Soldier: Agh![new] -Cecil: Are you all right?[new] -Soldier: There's more[new] + first_formatting = process_dialogue("""[bold]Soldier[normal]: Agh![new] +[bold]Cecil[normal]: Are you all right?[new] +[bold]Soldier[normal]: There's more[new] of them![new] -Cecil: Damn![end]""") +[bold]Cecil[normal]: Damn![end]""") second_formatting = process_dialogue(first_formatting) @@ -92,8 +87,11 @@ def test_formatting_speech_without_the_character_visible() -> None: """«Je suis votre guide pour l'enfer...» «Je suis l'un des quatre Empereurs de seigneur Golbeze... Scarmiglione de la Terre... Il est temps que dînent mes précieux morts-vivants!» Cecil: Comment!?[end]""" ) == """«Je suis votre guide pour l'enfer...»[new] -«Je suis l'un des quatre Empereurs de seigneur Golbeze... Scarmiglione de la Terre... Il est temps que dînent mes précieux morts-vivants!»[new] -Cecil: Comment!?[end]""" +«Je suis l'un des quatre Empereurs de +seigneur Golbez... Scarmiglione de la +Terre... Il est temps que dînent mes +précieux morts-vivants!»[new] +[bold]Cecil[normal]: Comment!?[end]""" ) @@ -119,13 +117,13 @@ def test_character_speech_sentences_not_fitting_the_current_window_should_be_mov process_dialogue( """Cecil: Votre Majesté, nous ne comprenons pas vos intentions. Pourquoi avez-vous besoin de ces cristaux? Était-ce parce que les Mythidiens représentaient une menace? Alors pourquoi n'ont-ils pas résisté? Nous ne comprenons pas pourquoi des innocents ont dû périr.[end]""" ) - == """Cecil: Votre Majesté, nous ne + == """[bold]Cecil[normal]: Votre Majesté, nous ne comprenons pas vos intentions. Pourquoi avez-vous besoin de ces cristaux?[new] Était-ce parce que les Mythidiens représentaient une menace? -Alors pourquoi n'ont-ils pas résisté?[new] +Alors pourquoi n'ont-ils pas résisté? Nous ne comprenons pas pourquoi des innocents ont dû périr.[end]""" ) @@ -135,10 +133,10 @@ def test_changing_character_should_introduce_a_new_tag() -> None: assert process_dialogue( """Soldat: Mais, Capitaine! Soldat: Piller une cité de magiciens qui n'opposent aucune résistance! Cecil: Écoutez bien, vous tous! Le cristal est absolument nécessaire à la prospérité de notre royaume de Baron. Sa Majesté a jugé que les habitants de Mythidia en savaient trop sur les secrets du cristal. Nous sommes l'escadron des Ailes Rouges de Baron, et les ordres de Sa Majesté sont absolus! Soldat: Capitaine...[end]""" ) == ( - "Soldat: Mais, Capitaine![new]\n" - "Soldat: Piller une cité de magiciens qui\n" + "[bold]Soldat[normal]: Mais, Capitaine![new]\n" + "[bold]Soldat[normal]: Piller une cité de magiciens qui\n" "n'opposent aucune résistance![new]\n" - "Cecil: Écoutez bien, vous tous!\n" + "[bold]Cecil[normal]: Écoutez bien, vous tous!\n" "Le cristal est absolument nécessaire à\n" "la prospérité de notre royaume de Baron.[new]\n" "Sa Majesté a jugé que les habitants de\n" @@ -147,15 +145,16 @@ def test_changing_character_should_introduce_a_new_tag() -> None: "Nous sommes l'escadron des Ailes\n" "Rouges de Baron, et les ordres de Sa\n" "Majesté sont absolus![new]\n" - "Soldat: Capitaine...[end]" + "[bold]Soldat[normal]: Capitaine...[end]" ) assert ( process_dialogue("""Caïn: Qu'est-ce qu'il y a? Cecil: Je suis désolé, Caïn... Caïn: Pourquoi t'excuses-tu encore? Je t'ai défendu de mon plein gré!![end]""") - == """Caïn: Qu'est-ce qu'il y a?[new] -Cecil: Je suis désolé, Caïn...[new] -Caïn: Pourquoi t'excuses-tu encore? + == """[bold]Caïn[normal]: Qu'est-ce qu'il y a?[new] +[bold]Cecil[normal]: Je suis désolé, Caïn...[new] +[bold]Caïn[normal]: Pourquoi t'excuses-tu +encore? Je t'ai défendu de mon plein gré!![end]""" ) @@ -166,14 +165,14 @@ def test_long_sentence_splitting_within_character_speech() -> None: process_dialogue( """Tellah: Je ne suis pas en mesure de vaincre quelqu'un d'aussi puissant que lui avec la magie dont je dispose actuellement. Je recherchais la légendaire magie scellée, Météor... Et j'ai senti une forte aura émise de cette montagne. Serait-ce possible, après toutes ces années de recherches..?[end]""" ) - == """Tellah: Je ne suis pas en mesure de + == """[bold]Tellah[normal]: Je ne suis pas en mesure de vaincre quelqu'un d'aussi puissant que lui avec la magie dont je dispose actuellement.[new] Je recherchais la légendaire magie scellée, Météor... Et j'ai senti une forte aura émise de -cette montagne.[new] +cette montagne. Serait-ce possible, après toutes ces années de recherches..?[end]""" ) @@ -185,7 +184,7 @@ def test_abbreviation_handling() -> None: process_dialogue( """Cecil: Bonjour M. Rosa, comment allez-vous? Nous devons partir maintenant.[end]""" ) - == """Cecil: Bonjour M. Rosa, + == """[bold]Cecil[normal]: Bonjour M. Rosa, comment allez-vous? Nous devons partir maintenant.[end]""" ) @@ -196,8 +195,9 @@ def test_bank2_variants_end_should_clear_the_state() -> None: process_dialogue("""Si le capitaine des chevaliers dragons Caïn et Cecil font équipe, cette bague est sûre d'arriver à bon port![end]M.Caïn est intouchable![end] On dit beaucoup de choses sur sa majesté, mais si elle entendait ça...[end]""") == """Si le capitaine des chevaliers dragons -Caïn et Cecil font équipe, cette -bague est sûre d'arriver à bon port![end] +Caïn et Cecil font équipe, +cette bague est sûre d'arriver à bon +port![end] M.Caïn est intouchable![end] On dit beaucoup de choses sur sa majesté, mais si elle entendait ça...[end]""" @@ -212,13 +212,13 @@ def test_pointer_49() -> None: Alors pourquoi n'ont-ils pas résisté? Nous ne comprenons pas pourquoi des innocents ont dû périr.[end]""" - expected = """Cecil: Votre Majesté, nous ne + expected = """[bold]Cecil[normal]: Votre Majesté, nous ne comprenons pas vos intentions. Pourquoi avez-vous besoin de ces cristaux?[new] Était-ce parce que les Mythidiens représentaient une menace? -Alors pourquoi n'ont-ils pas résisté?[new] +Alors pourquoi n'ont-ils pas résisté? Nous ne comprenons pas pourquoi des innocents ont dû périr.[end]""" @@ -235,10 +235,10 @@ def test_break_line_should_not_introduce_spaces() -> None: process_dialogue( """Yang: Il est trop tard! Cecil: Mais qui est en train de combattre les Ailes Rouges? Cid: Malheur! On est touché! On va s'écraser! Accrochez-vous![end]""" ) - == """Yang: Il est trop tard![new] -Cecil: Mais qui est en train de + == """[bold]Yang[normal]: Il est trop tard![new] +[bold]Cecil[normal]: Mais qui est en train de combattre les Ailes Rouges?[new] -Cid: Malheur! +[bold]Cid[normal]: Malheur! On est touché! On va s'écraser! Accrochez-vous![end]""" @@ -251,7 +251,17 @@ def test_bank_2_thingie() -> None: processed = process_dialogue(text) assert ( processed - == """T[end]T[end]T[end]T[end]T[end]T[end]T[end]T[end]T[end]T[end]Le trésor de Baron est entreposé ici! + == """T[end] +T[end] +T[end] +T[end] +T[end] +T[end] +T[end] +T[end] +T[end] +T[end] +Le trésor de Baron est entreposé ici! C'est interdit![end]""" ) @@ -261,8 +271,9 @@ def test_mixed_offscreen_and_character_dialog() -> None: "«Vous êtes de Baron, hein...» Caïn: Qui est là?[music][0x2d] «Partez maintenant et il ne vous fait aucun mal...» Caïn: Montre-toi! «Vous voulez vraiment continuer?»[end]" ) == ( "«Vous êtes de Baron, hein...»[new]\n" - "Caïn: Qui est là?[music][0x2d][new]\n" - "«Partez maintenant et il ne vous fait aucun mal...»[new]\n" - "Caïn: Montre-toi![new]\n" + "[bold]Caïn[normal]: Qui est là?[music][0x2d][new]\n" + "«Partez maintenant et il ne vous fait\n" + "aucun mal...»[new]\n" + "[bold]Caïn[normal]: Montre-toi![new]\n" "«Vous voulez vraiment continuer?»[end]" ) diff --git a/text/ff4_menus.tbl b/text/ff4_menus.tbl index e3c44c1..a082f75 100644 --- a/text/ff4_menus.tbl +++ b/text/ff4_menus.tbl @@ -1,5 +1,27 @@ 00=[end] 01=\n +29=[claw] +2a=[wand] +2b=[staff] +2c=[sword1] +2d=[sword2] +2e=[sword3] +2f=[spear] +30=[knife] +31=[katana] +32=[shuriken] +33=[boomerang] +34=[axe] +35=[wrench] +36=[note] +37=[bow] +38=[arrow] +39=[????] +3a=[whip] +3b=[shield] +3c=[helm] +3d=[armor] +3e=[gauntlet] 40=◎ 41=◉ 42=A @@ -68,7 +90,6 @@ C0=, C1=. C2=- -C3=.. C4=! C5=? C6=% @@ -86,6 +107,8 @@ C9=' 9D=Ï 9E=Î 9F=Ç +D0=œ +D1=Œ A0=é A1=è A2=ê @@ -96,7 +119,7 @@ A6=ô A7=ù A8=ï A9=î -B0=û +AF=û FB=[nowindow] FC=[new]\n FF= diff --git a/text/ff4fr.tbl b/text/ff4fr.tbl index 18538f4..bb86086 100644 --- a/text/ff4fr.tbl +++ b/text/ff4fr.tbl @@ -10,9 +10,13 @@ fe0207fe00=[item] 08=[gils] fe0208fe00=[gils] fe00=[normal] +fe00fe00=[force_normal] fe01=[wicked] +fe01fe01=[force_wicked] fe02=[book] +fe02fe02=[force_book] fe03=[bold] +fe03fe03=[force_bold] 0400=Cecil 0401=Cain 0401=Caïn @@ -127,6 +131,7 @@ fe03=[bold] 9E=Î 9F=Ç A0A1=œ +A2=↓ FC=[new]\n FD=° FF= diff --git a/text/fr/attack-names.xml b/text/fr/attack-names.xml index afd147b..213e1d0 100644 --- a/text/fr/attack-names.xml +++ b/text/fr/attack-names.xml @@ -80,7 +80,7 @@ Numéro 199 Flamme Brasier -Éclair +Eclair Tonnerre Souffle du Dragon Grande Vague diff --git a/text/fr/bank1-1.xml b/text/fr/bank1-1.xml index 45e43a0..02051c4 100644 --- a/text/fr/bank1-1.xml +++ b/text/fr/bank1-1.xml @@ -48,8 +48,8 @@ pour cacher son identité...[new] Pardonne-moi... de m'être enfuie, père... Je... j'aime... Edward![new] -[bold]Edward[normal]: Golbez... commande les -Ailes Rouges de Baron...[new] +[bold]Edward[normal]: Golbez... commande les Ailes +Rouges de Baron...[new] [bold]Cecil[normal]: Qui est Golbez?[new] [bold]Edward[normal]: Je ne sais pas... Il était entièrement vêtu de noir... d'une @@ -77,8 +77,9 @@ flèches...[end] Tu n'as pas assez de Gils![end] -«Bienvenue! C'est [0x08] Gils la nuit. Allez-vous rester?»[new] -[close_window][end] +Bienvenue! +C'est [gils] Gils la nuit. +Allez-vous rester?[close_window][end] «Au plaisir de vous revoir!»[end] @@ -90,29 +91,27 @@ flèches...[end] [bold]Soldat[normal]: Capitaine Cecil, nous approchons de Baron![new] -[bold]Cecil[normal]: Bien[delay][0x18].[delay][0x18].[delay][0x18].[end] +[bold]Cecil[normal]: Bien[delay][0x3].[delay][0x3].[delay][0x3].[end] [bold]Soldat[normal]: Le capitaine semble également préoccupé...[new] -[bold]Soldat[normal]: Même sur ordre de Sa -Majesté...[new] -[bold]Soldat[normal]: Arracher le cristal à un -peuple innocent... +[bold]Soldat[normal]: Même sur ordre de Sa Majesté...[new] +[bold]Soldat[normal]: Arracher le cristal à un peuple +innocent... C'est...[end] [bold]Soldat[normal]: Mais, Capitaine![new] [bold]Soldat[normal]: Piller une cité de magiciens qui n'opposent aucune résistance![new] [bold]Cecil[normal]: Écoutez bien, vous tous! -Le cristal est absolument nécessaire à -la prospérité de notre royaume de -Baron.[new] +Le cristal est absolument nécessaire à la +prospérité de notre royaume de Baron.[new] Sa Majesté a jugé que les habitants de -Mythidia en savaient trop sur les -secrets du cristal.[new] -Nous sommes l'escadron des Ailes -Rouges de Baron, et les ordres de Sa -Majesté sont absolus![new] +Mythidia en savaient trop sur les secrets +du cristal.[new] +Nous sommes l'escadron des Ailes Rouges +de Baron, et les ordres de Sa Majesté +sont absolus![new] [bold]Soldat[normal]: Capitaine...[end] [bold]Soldat[normal]: Capitaine! @@ -145,13 +144,11 @@ Par ici, Cecil, sa Majesté attend.[end] ...[end] -[bold]Beigan[normal]: Messire Cecil, attendez -ici.[end] +[bold]Beigan[normal]: Messire Cecil, attendez ici.[end] [bold]Beigan[normal]: Majesté! -Je redoute que Cecil n'ait -développé une défiance à l'égard du -trône...[new] +Je redoute que Cecil n'ait développé +une défiance à l'égard du trône...[new] [bold]Roi Baron[normal]: Vraiment!? Bravo, Beigan! Merci de m'en avoir informé! @@ -159,8 +156,8 @@ Mais le cristal avant tout...[new] Convoque-le ici![new] [bold]Beigan[normal]: Bien, Majesté.[end] -[bold]Beigan[normal]: Capitaine Cecil, Sa -Majesté attend. +[bold]Beigan[normal]: Capitaine Cecil, Sa Majesté +attend. Suivez-moi.[end] [bold]Roi Baron[normal]: Bien joué, Cecil. @@ -192,9 +189,9 @@ représentaient une menace? Alors pourquoi n'ont-ils pas résisté?[new] Nous ne comprenons pas pourquoi des innocents ont dû périr.[new] -Certains se sont même interrogés sur -le caractère... véritablement... honorable -de vos actions...[new] +Certains se sont même interrogés sur le +caractère... véritablement... honorable de +vos actions...[new] [bold]Roi Baron[normal]: Tu oserais donc douter de ton propre roi, Cecil?![new] [bold]Cecil[normal]: !! @@ -231,8 +228,8 @@ dans tout ça, Caïn.[new] [bold]Caïn[normal]: Ne t'en fais pas.[new] Une fois que tu auras éliminé ces Chimères, le Roi te pardonnera sûrement -et tu seras réintégré comme -commandant des Ailes Rouges.[new] +et tu seras réintégré comme commandant +des Ailes Rouges.[new] [bold]Cecil[normal]: ...[new] [bold]Caïn[normal]: Tu as eu une longue journée. Laisse-moi m'occuper des préparatifs et @@ -240,16 +237,14 @@ va te reposer un peu.[end] [bold]Caïn[normal]: Qu'est-ce qu'il y a?[new] [bold]Cecil[normal]: Je suis désolé, Caïn...[new] -[bold]Caïn[normal]: Pourquoi t'excuses-tu -encore? +[bold]Caïn[normal]: Pourquoi t'excuses-tu encore? Je t'ai défendu de mon plein gré!![new] [bold]Cecil[normal]: Ce n'est pas ça, Caïn. C'était ma mission d'aujourd'hui... -J'ai maîtrisé l'art de la lame noire -comme me l'avait ordonné Sa Majesté.[new] +J'ai maîtrisé l'art de la lame noire comme +me l'avait ordonné Sa Majesté.[new] Mais cela aurait dû servir à défendre -Baron, non à attaquer un peuple -innocent.[new] +Baron, non à attaquer un peuple innocent. Peut-être que mes excuses apaiseront ma conscience...[new] [bold]Caïn[normal]: Ne sois pas si sévère envers @@ -262,10 +257,9 @@ honorable...[new] [bold]Cecil[normal]: Caïn, j'envie ta foi en Sa Majesté. Il a évoqué ton père...[new] -Il possédait la même loyauté -indéfectible...[new] -[bold]Caïn[normal]: Mon père...Mon père était -aussi un chevalier dragon. +Il possédait la même loyauté indéfectible...[new] +[bold]Caïn[normal]: Mon père...Mon père était aussi +un chevalier dragon. Si j'avais maîtrisé l'art de la lame noire comme le roi me l'avait demandé...[new] J'aurais sûrement évolué comme toi... @@ -276,9 +270,9 @@ Il a péri quand j'étais encore enfant... Il y a des moments où j'espère qu'il m'observe... J'espère qu'il serait fier de moi...[new] -J'ai souvent ces moments... ...moments -de réflexion silencieuse où je peux sentir -son esprit en moi qui me guide...[new] +J'ai souvent ces moments... ...moments de +réflexion silencieuse où je peux sentir son +esprit en moi qui me guide...[new] [bold]Cecil[normal]: ...[new] [bold]Caïn[normal]: Pardonne-moi d'avoir divagué ainsi... @@ -287,8 +281,8 @@ Quoi qu'il en soit, je ne me tourmente pas outre mesure pour aujourd'hui. Tu ferais mieux de te préoccuper de demain![new] -Tu as accompli ce que le roi souhaitait, -et tu es devenu un chevalier noir...[new] +Tu as accompli ce que le roi souhaitait, et +tu es devenu un chevalier noir...[new] Tu détiens un rang et un prestige supérieurs aux miens, mais demain, nous verrons bien qui excelle! @@ -296,10 +290,9 @@ On part tôt demain, va te reposer.[end] [bold]Rosa[normal]: Cecil![end] -[bold]Rosa[normal]: Dieu merci, tu es sain et -sauf! -Ta mission était si soudaine, je -m'inquiétais terriblement.[new] +[bold]Rosa[normal]: Dieu merci, tu es sain et sauf! +Ta mission était si soudaine, je m'inquiétais +terriblement.[new] [bold]Cecil[normal]: Nous allons bien... Nous ne risquions guère d'être blessés par une poignée de magiciens... ...qui n'ont @@ -319,15 +312,15 @@ Mais maintenant... Le cristal de Mythidia...[new] Revêt-il donc une telle importance qu'il faille l'arracher à d'innocents villageois? -Et dire que nous avons dû commettre -un tel acte, sur ordre royal!![end] +Et dire que nous avons dû commettre un +tel acte, sur ordre royal!![end] [bold]Rosa[normal]: Que s'est-il passé? D'abord, tu es envoyé à Mythidia, puis soudain, tu es envoyé éliminer d'horribles créatures.[new] -Et tu te comportes de manière si -étrange depuis ton retour.[new] +Et tu te comportes de manière si étrange +depuis ton retour.[new] [bold]Cecil[normal]: Non... Ce n'est rien...[end] @@ -335,21 +328,19 @@ Ce n'est rien...[end] Regarde-moi plutôt.[end] [bold]Cecil[normal]: À Mythidia... -J'ai ôté la vie à des innocents et -dérobé leur cristal sacré... mais pour -quelle raison?![new] -Mon cur s'est assombri tout autant que +J'ai ôté la vie à des innocents et dérobé +leur cristal sacré... mais pour quelle +raison?![new] +Mon cœur s'est assombri tout autant que cette armure maudite![end] [bold]Rosa[normal]: ...Tu n'est pas comme cela.[end] -[bold]Cecil[normal]: Je ne suis rien qu'un -chevalier noir docile, tout juste un pantin -du roi.[end] +[bold]Cecil[normal]: Je ne suis rien qu'un chevalier +noir docile, tout juste un pantin du roi.[end] -[bold]Rosa[normal]: Le Cecil des Ailes -Rouges n'aurait jamais pleurniché comme -ça! +[bold]Rosa[normal]: Le Cecil des Ailes Rouges +n'aurait jamais pleurniché comme ça! Pas le Cecil que j'aime...[end] [bold]Rosa[normal]: Tu t'en vas à Mist demain, @@ -365,8 +356,7 @@ Va donc te coucher.[end] Pour l'amour de moi...[end] [bold]Cecil[normal]: Merci, Rosa. -Pourtant, je ne suis qu'un chevalier -noir... +Pourtant, je ne suis qu'un chevalier noir... Qu'est-ce que je peux y faire?[end] [bold]Cecil[normal]: Yang, tu vas bien![new] @@ -403,10 +393,9 @@ Edward... je ne sais pas...[new] [bold]Cecil[normal]: À Baron. Si les soldats nous entendent, on aura des ennuis.[new] -Il y a une chambre tranquille à -l'auberge. -Allons-y! [0xfa]Le Moine Yang a rejoint -le groupe![music][0x29][delay][0x28][end] +Il y a une chambre tranquille à l'auberge. +Allons-y! [0xfa]Le Moine Yang a rejoint le +groupe![music][0x29][delay][0x28][end] [bold]Yang[normal]: Et qui est ce monsieur?[new] [bold]Cecil[normal]: Tellah, le sage. @@ -449,8 +438,8 @@ NON!![new] donc maman aussi... -sanglot-, -sanglot-...[end] [bold]Cecil[normal]: Bon sang![new] -[bold]Caïn[normal]: Maintenant que j'y pense, -j'en ai entendu parler. +[bold]Caïn[normal]: Maintenant que j'y pense, j'en +ai entendu parler. Des gens qui ont le pouvoir d'invoquer des monstres...[new] Ce sont les Invocateurs![new] @@ -461,17 +450,16 @@ de cette fille?[end] [bold]Fille[normal]: Alors c'est vous qui avez tué le dragon de maman?![new] -[bold]Cecil[normal]: On ne savait pas... qu'en -tuant ce dragon... on causerait la mort -de ta mère...[end] +[bold]Cecil[normal]: On ne savait pas... qu'en tuant +ce dragon... on causerait la mort de ta +mère...[end] -[bold]Caïn[normal]: Le Roi nous a envoyés ici -pour exterminer les invocateurs...[new] +[bold]Caïn[normal]: Le Roi nous a envoyés ici pour +exterminer les invocateurs...[new] [bold]Cecil[normal]: Miséricorde![new] [bold]Caïn[normal]: Malheureusement, les ordres sont les ordres... -On n'a d'autre choix que de la tuer -aussi.[end] +On n'a d'autre choix que de la tuer aussi.[end] [bold]Cecil[normal]: Caïn![new] [bold]Caïn[normal]: Si on désobéit, on sera @@ -482,26 +470,26 @@ braver le Roi?[new] [bold]Cecil[normal]: Si le roi attend de nous qu'on assassine des gens comme ça... Je n'ai aucune intention de le suivre![new] -Je renonce à toute loyauté envers le -roi, les Ailes Rouges, et Baron!!![end] +Je renonce à toute loyauté envers le roi, +les Ailes Rouges, et Baron!!![end] -[bold]Caïn[normal]: Je me doutais que tu allais -dire ça. +[bold]Caïn[normal]: Je me doutais que tu allais dire +ça. Je ne vais pas te laisser affronter le roi tout seul.[new] [bold]Cecil[normal]: Caïn?[new] -[bold]Caïn[normal]: Peu importe ce que je dois -au roi, en tant que chevalier dragon... -Jamais je ne pourrais commettre un -acte aussi bas.[new] -[bold]Cecil[normal]: Alors tu n'avais pas -réellement l'intention de...[new] -[bold]Caïn[normal]: Baron est la plus grande -force militaire au monde. +[bold]Caïn[normal]: Peu importe ce que je dois au +roi, en tant que chevalier dragon... +Jamais je ne pourrais commettre un acte +aussi bas.[new] +[bold]Cecil[normal]: Alors tu n'avais pas réellement +l'intention de...[new] +[bold]Caïn[normal]: Baron est la plus grande force +militaire au monde. On ne peut pas combattre son pouvoir rien qu'à deux.[new] -Il faut prévenir les autres pays et -obtenir à tout prix leur aide. +Il faut prévenir les autres pays et obtenir +à tout prix leur aide. Et il faut sauver Rosa![new] [bold]Cecil[normal]: Merci, Caïn.[new] [bold]Caïn[normal]: Ce n'est pas spécialement @@ -534,36 +522,36 @@ Où es-tu? !![end] [bold]Cecil[normal]: Je ne peux pas rester ici éternellement... -Je dois emmener cette enfant et fuir -d'ici...[new] +Je dois emmener cette enfant et fuir d'ici... Caïn... sois vivant![end] [bold]Cecil[normal]: Si elle ne se repose pas...[end] -«Bienvenue! Oh, elle a l'air malade! Vite, vite, allez dans la chambre! Ne vous inquiétez pas pour l'argent!»[new] +«Bienvenue! Oh, elle a l'air malade! Vite, +vite, allez dans la chambre! Ne vous +inquiétez pas pour l'argent!»[new] [bold]Cecil[normal]: Merci.[end] [bold]Cecil[normal]: Tu as enfin repris...[new] [bold]Fille[normal]: ...[new] -[bold]Cecil[normal]: Je ne sais même pas -comment tu t'appelles.[new] +[bold]Cecil[normal]: Je ne sais même pas comment +tu t'appelles.[new] [bold]Fille[normal]: ...[new] [bold]Cecil[normal]: Je ne peux pas te demander de me pardonner d'avoir tué ta mère.... -Mais je t'en prie, laisse-moi te -protéger...[new] +Mais je t'en prie, laisse-moi te protéger...[new] [bold]Fille[normal]: ...[end] -[bold]Général[normal]: Enfin, Cecil, nous -t'avons trouvé!![new] +[bold]Général[normal]: Enfin, Cecil, nous t'avons +trouvé!![new] [bold]Fille[normal]: !![new] [bold]Cecil[normal]: Attendez! Le roi de Baron a...[new] [bold]Général[normal]: Ordres du roi. -Si tu nous livres la survivante de Mist, -il pardonnera ta traîtrise.[new] -Il a été jugé dangereux que le peuple -de Mist puisse seulement exister![new] +Si tu nous livres la survivante de Mist, il +pardonnera ta traîtrise.[new] +Il a été jugé dangereux que le peuple de +Mist puisse seulement exister![new] [bold]Cecil[normal]: Quoi!? Le roi est donc tombé si bas au point de tuer des enfants?![new] @@ -582,8 +570,8 @@ Ce que j'ai fait est impardonnable.[new] [bold]Fille[normal]: Je m'appelle... Rydia...[new] [bold]Cecil[normal]: Merci... -Rydia. [0xfa]L'invocatrice Rydia se -joint à toi![end] +Rydia. [0xfa]L'invocatrice Rydia se joint +à toi![end] [0xfa]Cecil a fait briller la Lumière du Désert sur Rosa![end] @@ -605,27 +593,25 @@ pour te remplacer à la tête des Ailes Rouges.[new] Depuis qu'il est arrivé, le Roi lui a donné de plus en plus de pouvoir... -C'est sûrement Golbez qui influence -le roi pour réunir les quatre cristaux.[new] +C'est sûrement Golbez qui influence le +roi pour réunir les quatre cristaux.[new] Le cristal de l'eau de Mythidia... Le cristal du feu de Damcyan... Le cristal du vent de Fabul... et le cristal de la terre de Troia.[end] -[bold]Edward[normal]: Il a déjà pris le cristal du -feu...[new] +[bold]Edward[normal]: Il a déjà pris le cristal du feu...[new] [bold]Cecil[normal]: C'est Edward, le prince de Damcyan. C'est grâce à lui que nous avons pu te soigner.[new] -Et cette fille s'appelle Rydia, elle -vient de Mist.[new] +Et cette fille s'appelle Rydia, elle vient +de Mist.[new] [bold]Rydia[normal]: Tu vas bien?[new] [bold]Rosa[normal]: Je vais mieux... merci... -Si le cristal de Damcyan a déjà été -volé... -La prochaine cible, c'est...[new] -Fabul! +Si le cristal de Damcyan a déjà été volé... +La prochaine cible, c'est... +Fabul![new] Nous devons empêcher que ça ne se produise... -keuf-, -keuf-[end] @@ -633,9 +619,8 @@ produise... -keuf-, -keuf-[end] Ne te surmène pas... Tu dois te reposer. Nous allons aller à Fabul.[new] -[bold]Edward[normal]: Mais le passage vers Fabul -par le Mont Hobs est bloqué par la -glace...[end] +[bold]Edward[normal]: Mais le passage vers Fabul par +le Mont Hobs est bloqué par la glace...[end] [bold]Rosa[normal]: Rydia, tu peux lancer le sort du[new] @@ -644,8 +629,8 @@ sort du[new] [bold]Rydia[normal]: ! ...Hmm...non, je peux pas...[end] [bold]Rosa[normal]: Si tu es une invocatrice, tu -devrais pouvoir lancer des sorts -basiques de magie noire tels que[new] +devrais pouvoir lancer des sorts basiques +de magie noire tels que[new] «Feu»[new] ... -keuf-[end] @@ -657,8 +642,8 @@ Tu me manques tellement...[end] [bold]Edward[normal]: Anna![new] [bold]Anna[normal]: Edward, je dois partir... -L'heure est venue... ...pour que je ne -fasse plus qu'un avec un esprit éternel...[new] +L'heure est venue... ...pour que je ne fasse +plus qu'un avec un esprit éternel...[new] [bold]Edward[normal]: Anna! Ne me laisse pas![end] @@ -666,17 +651,16 @@ Ne me laisse pas![end] ne laisse pas Golbez rassembler les cristaux... Tu m'aimais.[new] -À présent, donne cet amour aux gens -de la Terre.[end] +À présent, donne cet amour aux gens de +la Terre.[end] -[bold]Edward[normal]: Oui, Anna, je me -battrai... +[bold]Edward[normal]: Oui, Anna, je me battrai... Mais le courage... Que dois-je faire, Anna?[end] [bold]Tellah[normal]: Elle s'est bien vite endormie... -Ç'a dû être une journée éprouvante -pour quelqu'un de si jeune... +Ç'a dû être une journée éprouvante pour +quelqu'un de si jeune... Cette petite est-elle...[new] [bold]Cecil[normal]: Une invocatrice de Mist.[new] [bold]Tellah[normal]: Je ressens en elle un grand @@ -684,16 +668,14 @@ potentiel. Elle pourrait devenir une sorcière très douée... ...[new] Un visage si paisible... -Comme Anna quand elle était -petite.[new] +Comme Anna quand elle était petite.[new] [bold]Cecil[normal]: Anna est...[new] [bold]Tellah[normal]: Ma fille unique. Elle s'est sauvée à Damcyan avec un barde parce que je n'ai pas consenti à leur mariage...[end] -[bold]Tellah[normal]: Pourquoi vous y -rendez-vous?[new] +[bold]Tellah[normal]: Pourquoi vous y rendez-vous?[new] [bold]Cecil[normal]: J'ai une amie à Kaïpo qui souffre d'une fièvre terrible.[new] [bold]Tellah[normal]: Alors il vous faut la Lumière @@ -706,8 +688,8 @@ avec huit énormes pattes. Il nous faudra le battre si nous voulons sauver Anna et votre amie...[new] J'espère que ce mauvais pressentiment -que j'ai sur Damcyan n'est que le fruit -de mon imagination mais...[end] +que j'ai sur Damcyan n'est que le fruit de +mon imagination mais...[end] [bold]Cid[normal]: Mais de quoi vous vous inquiétez? @@ -722,15 +704,14 @@ Craque pas pour moi maintenant![end] [bold]Cecil[normal]: Roi Giotto, où est le cristal dans ce château?[new] -[bold]Giotto[normal]: Il est caché dans une salle -secrète derrière ce trône même! +[bold]Giotto[normal]: Il est caché dans une salle secrète +derrière ce trône même! Tant que je peux le surveiller, tout ira bien![end] [bold]Yang[normal]: ![end] -[bold]Cecil[normal]: Qu'est-ce qu'il y a, -Yang?[new] +[bold]Cecil[normal]: Qu'est-ce qu'il y a, Yang?[new] [bold]Yang[normal]: Quelqu'un écoute![new] [bold]Giotto[normal]: Qui!?[end] @@ -745,8 +726,7 @@ Cette expression sur ton visage...[new] [bold]Yang[normal]: Oui! Mais plus important, Roi Fabul![new] Un homme nommé Golbez mobilise les -forces de Baron afin de voler notre -cristal![new] +forces de Baron afin de voler notre cristal![new] [bold]Roi Fabul[normal]: Quoi!? Comment est-ce possible?[new] [bold]Yang[normal]: Ces personnes sont venues @@ -770,17 +750,17 @@ Nous devons nous préparer au combat![new] [bold]Edward[normal]: Ça faisait longtemps, roi Fabul.[new] [bold]Roi Fabul[normal]: Prince Edward![new] -[bold]Edward[normal]: Damcyan a déjà été attaqué -et notre cristal a été volé! -J'ai perdu... mon père... ma mère... et -celle que j'aimais...![new] +[bold]Edward[normal]: Damcyan a déjà été attaqué et +notre cristal a été volé! +J'ai perdu... mon père... ma mère... et celle +que j'aimais...![new] Allez-vous laisser Fabul subir le même sort que Damcyan?![end] [bold]Yang[normal]: Eh bien, Cecil![end] -[bold]Yang[normal]: Ces gens sont des maîtres -au combat! +[bold]Yang[normal]: Ces gens sont des maîtres au +combat! Laissez-les se battre avec moi sur le front!![new] [bold]Roi Fabul[normal]: Puisque tu insistes, je laisse @@ -807,8 +787,8 @@ faire tuer, comme ça![new] [bold]Yang[normal]: Retraite! Repli dans le château![end] -[bold]Yang[normal]: Désolé de vous avoir -entraînés dans un combat sans espoir![new] +[bold]Yang[normal]: Désolé de vous avoir entraînés +dans un combat sans espoir![new] [bold]Cecil[normal]: Comme je l'ai déjà dit, c'est aussi notre combat! Et nous n'avons pas encore perdu![new] @@ -817,12 +797,11 @@ Et nous n'avons pas encore perdu![new] [bold]Yang[normal]: Merde! Replions-nous![end] -[bold]Cecil[normal]: Ce n'est pas la salle du -trône, là derrière...!?[new] +[bold]Cecil[normal]: Ce n'est pas la salle du trône, +là derrière...!?[new] [bold]Yang[normal]: Ne t'inquiète pas! Le roi a déjà trouvé refuge avec les -femmes et les enfants dans un endroit -sûr![new] +femmes et les enfants dans un endroit sûr! Il faut nous occuper de ces monstres![end] [bold]Yang[normal]: Attaquez![end] @@ -859,7 +838,8 @@ souffrances![new] [bold]Caïn[normal]: Ourg...ahh..! Ne...me...regarde...pas[end] -«Qu'y a-t-il, Caïn? Qu'est-ce qui te trouble?»[end] +«Qu'y a-t-il, Caïn? Qu'est-ce qui te +trouble?»[end] [bold]Edward[normal]: Golbez![new] [bold]Cecil[normal]: Tu es Golbez![new] @@ -887,9 +867,9 @@ J'aimerais te revoir, Cecil...[new] Elle sera la preuve de notre promesse. Allons-y, Caïn![end] -[bold]Caïn[normal]: Apparemment, tu vas -survivre un peu plus longtemps que -prévu, Cecil![end] +[bold]Caïn[normal]: Apparemment, tu vas survivre +un peu plus longtemps que prévu, +Cecil![end] [bold]Cecil[normal]: At...tendez![end] @@ -915,8 +895,8 @@ Et puis on peut récupérer le cristal![end] Reposez-vous.[end] [bold]Edward[normal]: Il faut sauver Rosa! -Pour lutter contre Golbez, nous -avons besoin d'un Aéronef. +Pour lutter contre Golbez, nous avons +besoin d'un Aéronef. Mais seul Baron en a...[new] [bold]Yang[normal]: Je me demande s'il n'y aurait pas moyen de s'introduire dans Baron...[end] @@ -930,14 +910,13 @@ faudra le faire par la mer.[new] alors![new] [bold]Yang[normal]: Demandons au roi dès demain matin. -Tu es venu à son secours, il t'en -allouera sûrement un.[new] +Tu es venu à son secours, il t'en allouera +sûrement un.[new] [bold]Cecil[normal]: Merci.[end] -[bold]Yang[normal]: Qui était ce chevalier -dragon?[new] -[bold]Cecil[normal]: Il s'appelle Caïn et -c'est... c'était... mon meilleur ami. +[bold]Yang[normal]: Qui était ce chevalier dragon?[new] +[bold]Cecil[normal]: Il s'appelle Caïn et c'est... +c'était... mon meilleur ami. Nous nous étions juré de fuir de Baron ensemble.[new] [bold]Yang[normal]: Je vois...[new] @@ -959,8 +938,7 @@ Vous serez à Baron avant de vous en rendre compte! Larguez les amarres![end] -[bold]Capitaine[normal]: Allez les gars, levez -l'ancre![new] +[bold]Capitaine[normal]: Allez les gars, levez l'ancre![new] [bold]Équipage[normal]: Hourra![end] [bold]Yang[normal]: Que comptez-vous faire une @@ -1006,15 +984,14 @@ Ooh...[end] [bold]Scarmiglione[normal]: -Gargl-... Scarmiglione de la Terre, à ton service...[new] -[bold]Golbez[normal]: Ce Cecil pourrait -devenir un problème. +[bold]Golbez[normal]: Ce Cecil pourrait devenir +un problème. Il faut s'occuper de lui avant qu'il n'en devienne un.[new] C'est un chevalier noir, il devrait donc -être impuissant contre nos morts -vivants.[new] -Mais il gravit en ce moment la -Montagne de l'Épreuve.[new] +être impuissant contre nos morts vivants. +Mais il gravit en ce moment la Montagne +de l'Épreuve.[new] [bold]Scarmiglione[normal]: Il veut... donc devenir... -hiss-... paladin?[new] [bold]Golbez[normal]: Bien évidemment, ta mission @@ -1054,8 +1031,8 @@ C'est toi, Tellah?[end] Appelle-le maître Tellah! Tu es d'un grossier![end] -[bold]Porom[normal]: Nous sommes honorés de -vous rencontrer, maître Tellah. +[bold]Porom[normal]: Nous sommes honorés de vous +rencontrer, maître Tellah. Nous avons été envoyés ici par l'Ancien de Mythidia pour...[new] [bold]Palom[normal]: Surveiller Cecil...[end] @@ -1084,8 +1061,8 @@ Golbez...[end] [bold]Palom[normal]: C'est sûrement sa copine![end] [bold]Porom[normal]: Chut![new] -[bold]Cecil[normal]: Mais tu ne devais pas aller à -la recherche de Golbez?[end] +[bold]Cecil[normal]: Mais tu ne devais pas aller à la +recherche de Golbez?[end] [bold]Tellah[normal]: Je ne suis pas en mesure de vaincre quelqu'un d'aussi puissant que lui @@ -1093,8 +1070,8 @@ avec la magie dont je dispose actuellement.[new] Je recherchais la légendaire magie scellée, Météor... -Et j'ai senti une forte aura émise de -cette montagne.[new] +Et j'ai senti une forte aura émise de cette +montagne.[new] Serait-ce possible, après toutes ces années de recherches..?[new] [bold]Porom[normal]: Ce sort est dangereux! @@ -1115,17 +1092,24 @@ C'est l'homme qui contrôle Baron![end] «Gargl...»[new] [bold]Tellah[normal]: ...Une présence maléfique!![new] -«Je suis heureux... Très heureux... Tuer me rend heureux!»[new] +«Je suis heureux... Très heureux... Tuer me +rend heureux!»[new] [bold]Cecil[normal]: Qui est là!?[end] «Je suis votre guide pour l'enfer...»[new] -«Je suis l'un des quatre Empereurs de seigneur Golbez... Scarmiglione de la Terre... Il est temps que dînent mes précieux morts-vivants!»[end] +«Je suis l'un des quatre Empereurs de +seigneur Golbez... Scarmiglione de la +Terre... Il est temps que dînent mes +précieux morts-vivants!»[end] -«Fshhh... Bien joué... de m'avoir tué... Mais voyez la terrifiante puissance de Scarmiglione de la Terre... même dans la mort... Savourez lentement... votre agonie!»[end] +«Fshhh... Bien joué... de m'avoir tué... Mais +voyez la terrifiante puissance de +Scarmiglione de la Terre... même dans la +mort... Savourez lentement... votre agonie!»[end] [bold]Scarmiglione[normal]: Maudit... -Que moi, Scarmiglione... je sois vaincu -par des vermines comme vous...![end] +Que moi, Scarmiglione... je sois vaincu par +des vermines comme vous...![end] «Je t'attendais...»[new] «Le chagrin me remplit...»[new] @@ -1133,7 +1117,11 @@ par des vermines comme vous...![end] «Mon chagrin ne fera alors que grandir...»[new] «Mais c'est la seule solution qui reste.»[end] -«Laisse ton passé sanglant derrière toi... Purifie ton âme avec la lumière sacrée! Tu dois le faire! Pour recevoir cette force sacrée, combats et détruis ton double obscur en tant que chevalier noir!»[end] +«Laisse ton passé sanglant derrière toi... +Purifie ton âme avec la lumière sacrée! Tu +dois le faire! Pour recevoir cette force +sacrée, combats et détruis ton double +obscur en tant que chevalier noir!»[end] [bold]Tellah[normal]: Deux Cecil?[new] [bold]Palom[normal]: Que se passe-t-il?[new] @@ -1144,7 +1132,9 @@ C'est mon combat! Pour expier mon passé, je dois surmonter ma propre noirceur![end] -«Bien joué... Reçois ma conscience... Prends-la... ma... lumière finale! Mon fils... arrête Golbez!»[new] +«Bien joué... Reçois ma conscience... +Prends-la... ma... lumière finale! Mon fils... +arrête Golbez!»[new] [bold]Cecil[normal]: A...attends![end] [0xfa]Cecil est devenu un paladin![end] @@ -1159,12 +1149,12 @@ Quelle était cette voix..?[new] [bold]Porom[normal]: Maître Tellah?[end] [bold]Tellah[normal]: Je commence à me souvenir... -Tous mes sorts commencent à me -revenir! [0xfa]Tellah a retrouvé tous les -[0xfa]sorts qu'il avait oubliés![end] +Tous mes sorts commencent à me revenir! +[0xfa]Tellah a retrouvé tous les [0xfa]sorts qu'il +avait oubliés![end] -[bold]Porom[normal]: Comme on pouvait s'y -attendre de Maître Tellah...[new] +[bold]Porom[normal]: Comme on pouvait s'y attendre +de Maître Tellah...[new] [bold]Palom[normal]: Hé, Porom...[end] [bold]Porom[normal]: Cecil..[new] @@ -1202,8 +1192,8 @@ Alors Rydia est aussi..?[new] [bold]Yang[normal]: J'ai honte...[end] [bold]Edward[normal]: Oh...c'est horrible... -Et dire que je ne peux rien faire -pendant que vous combattez...[end] +Et dire que je ne peux rien faire pendant +que vous combattez...[end] [bold]Edward[normal]: Vous êtes Cid? Alors vous devez pouvoir... !![end] @@ -1225,7 +1215,8 @@ en danger![end] [bold]Edward[normal]: ...Ne vous inquiétez pas... Juste jusqu'à ma harpe là-bas... Ooh![new] -«Dans votre état, vous ne devriez même pas marcher! Ne vous surmenez pas!»[new] +«Dans votre état, vous ne devriez même +pas marcher! Ne vous surmenez pas!»[new] [bold]Edward[normal]: Ça ne fait rien... Je suis le seul... qui puisse sauver... Cecil et les autres![end] @@ -1259,13 +1250,13 @@ Vous avez gagné...[new] [bold]Cecil[normal]: Edward! C'est grâce à vous![new] [bold]Edward[normal]: Non, pas vraiment...[new] -[bold]Cid[normal]: Mais pourquoi cette mélodie -lui a fait quelque chose?[end] +[bold]Cid[normal]: Mais pourquoi cette mélodie lui +a fait quelque chose?[end] [bold]Edward[normal]: Alors que je parcourais le -monde déguisé en barde, j'ai entendu -des mélodies qui repoussent les démons -et les esprits maléfiques.[new] +monde déguisé en barde, j'ai entendu des +mélodies qui repoussent les démons et les +esprits maléfiques.[new] J'ai pensé que cette mélodie pourrait marcher. Ç'a été le cas...[new] @@ -1279,10 +1270,9 @@ Ooh![end] D'être aimée par quelqu'un de si courageux...[new] [bold]Edward[normal]: Tellah...[new] -[bold]Tellah[normal]: Pour l'instant, -concentrez-vous juste sur votre -guérison. -Je vengerai Anna avec Météor![new] +[bold]Tellah[normal]: Pour l'instant, concentrez-vous +juste sur votre guérison. +Je vengerai Anna avec Météor! Edward... pour vous aussi.[new] [bold]Edward[normal]: ...Merci.[new] [bold]Cecil[normal]: Edward, vous êtes... un @@ -1299,36 +1289,36 @@ Golbez veut vous remercier en personne.[new] [bold]Tellah[normal]: Golbez![end] -[bold]Golbez[normal]: Je suis heureux que vous -ayez tenu votre promesse...[new] +[bold]Golbez[normal]: Je suis heureux que vous ayez +tenu votre promesse...[new] [bold]Tellah[normal]: Montre-toi![new] [bold]Golbez[normal]: Je comprends votre -impatience, mais j'aimerais vous -remercier.[new] +impatience, mais j'aimerais vous remercier.[new] [bold]Yang[normal]: Nous remercier?[new] [bold]Golbez[normal]: Je suis avec votre chère Rosa au sommet de cette Tour de Zot.[new] -Si vous parvenez jusqu'ici, j'échangerai -la vie de Rosa contre le cristal.[new] +Si vous parvenez jusqu'ici, j'échangerai la +vie de Rosa contre le cristal.[new] [bold]Cecil[normal]: Golbez, tu n'es qu'un salaud![new] [bold]Golbez[normal]: Si vous ne venez pas -rapidement, je ne peux garantir la vie -de votre précieuse Rosa...[music][0x19] Alors, -montez![end] +rapidement, je ne peux garantir la vie de +votre précieuse Rosa...[music][0x19] Alors, montez![end] «Bienvenue dans la tour de Zot!»[end] «Heureuses de vous rencontrer!»[end] -«C'est nous, les servantes de Barbariccia, l'Impératrice de l'air!»[new] +«C'est nous, les servantes de Barbariccia, +l'Impératrice de l'air!»[new] «Je suis Dog, des trois sœurs Magus!»[new] «Je suis Mag, pareil!»[new] «Je suis Rag!»[new] «Désolées, votre quête va s'arrêter là.»[new] «On va vous prendre le cristal.»[new] -«Encaissez notre attaque delta et puis adieu! Vous n'atteindrez pas Rosa!»[end] +«Encaissez notre attaque delta et puis +adieu! Vous n'atteindrez pas Rosa!»[end] «Impossible!»[new] «Vous avez déjoué notre attaque delta...»[new] @@ -1371,8 +1361,7 @@ Peu importe, tu ne me servais plus à rien. Cette dette, je la rembourserai![end] -[bold]Cecil[normal]: Tu n'iras nulle part, -Golbez![end] +[bold]Cecil[normal]: Tu n'iras nulle part, Golbez![end] [bold]Golbez[normal]: Guh... Ne me sous-estimez pas![end] @@ -1396,9 +1385,9 @@ Mais Tellah![end] [bold]Tellah[normal]: Je n'ai pas pu le tuer...[new] [bold]Cid[normal]: Ne parle pas![new] -[bold]Tellah[normal]: C'est peut-être... la -rétribution pour avoir combattu... -consumé par la haine... +[bold]Tellah[normal]: C'est peut-être... la rétribution +pour avoir combattu... consumé par la +haine... La vengeance d'Anna... je vous en...[end] [bold]Cecil[normal]: Tellah![new] @@ -1454,7 +1443,9 @@ services, revenez donc me voir.[end] [bold]Cecil[normal]: Allons-y, Caïn![end] -«Infliger des blessures à seigneur Golbez... Il semble que nous vous ayons sous-estimés!»[new] +«Infliger des blessures à seigneur +Golbez... Il semble que nous vous ayons +sous-estimés!»[new] [bold]Caïn[normal]: C'est un des quatre Empereurs de Golbez! Barbariccia du vent![end] @@ -1470,8 +1461,8 @@ familièrement! J'aurais dû vous éliminer, toi et Rosa![new] Mais l'utilisateur de Météor n'est plus. -Maintenant que vous êtes tous réunis, -je vais vous enterrer ensemble![new] +Maintenant que vous êtes tous réunis, je +vais vous enterrer ensemble![new] [bold]Caïn[normal]: Les combats aériens ne sont pas ton exclusivité![end] @@ -1497,11 +1488,11 @@ Il faut que je te parle de quelque chose.[end] [bold]Caïn[normal]: Il s'agit des cristaux...[new] [bold]Cecil[normal]: Le cristal emprunté à Troia a été volé aussi... -Cela signifie qu'il possède maintenant -tous les cristaux.[new] +Cela signifie qu'il possède maintenant tous +les cristaux.[new] [bold]Caïn[normal]: Non, il n'en a que quatre![new] -[bold]Rosa[normal]: Quatre ne font pas le -compte total...?[new] +[bold]Rosa[normal]: Quatre ne font pas le compte +total...?[new] [bold]Cid[normal]: Alors cette rumeur est vraie![new] [bold]Rosa[normal]: Ce ne peut pas être...[new] [bold]Caïn[normal]: Si... les Cristaux d'Obscurité![end] @@ -1512,10 +1503,10 @@ face externe de la Terre.[new] l'autre côté..?[new] [bold]Cecil[normal]: Les cristaux d'Obscurité..?[new] [bold]Caïn[normal]: En effet. -Donc, ça veut dire que Golbez n'a -que la moitié des cristaux![new] -[bold]Cid[normal]: Alors les cristaux -d'Obscurité, c'est pas une rumeur... +Donc, ça veut dire que Golbez n'a que +la moitié des cristaux![new] +[bold]Cid[normal]: Alors les cristaux d'Obscurité, +c'est pas une rumeur... Et la question inévitable... Où sont-ils?[new] [bold]Caïn[normal]: Golbez le sait.[new] @@ -1526,14 +1517,14 @@ Terre, mot à mot, le monde souterrain.[new] [bold]Cid[normal]: Mais comment on va bien pouvoir y aller? En creusant un trou, ou quoi?[new] -[bold]Caïn[normal]: Je n'en sais rien... +[bold]Caïn[normal]: Je n'en sais rien...[new] En tout cas, Golbez a dit qu'une fois les cristaux de la face et de l'arrière réunis, le chemin vers la Lune s'ouvrirait.[new] [bold]Cecil[normal]: Le chemin vers la Lune?[new] [bold]Caïn[normal]: Je ne suis pas sûr de ce que -ça veut dire... mais apparemment cet -objet servirait dans notre quête. +ça veut dire... mais apparemment cet objet +servirait dans notre quête. Tiens, prends-le.[end] [0xfa]Tu reçois la Pierre du Magma. @@ -1561,28 +1552,28 @@ Tiens bon![new] souterrain, le roi des Nains, Giotto...[new] [bold]Cecil[normal]: Où sont les cristaux d'Obscurité?[new] -[bold]Giotto[normal]: Ah, c'est donc pour ça qu'ils -sont venus. +[bold]Giotto[normal]: Ah, c'est donc pour ça qu'ils sont +venus. On se disait que vous étiez avec eux, mais ils vous ont abattus.[new] En fait, on était nous-mêmes prêts à vous tirer dessus.[new] [bold]Caïn[normal]: Les cristaux sont à l'abri?[new] -[bold]Giotto[normal]: Hélas, ils ont déjà pris deux -des quatre cristaux.[new] +[bold]Giotto[normal]: Hélas, ils ont déjà pris deux des +quatre cristaux.[new] [bold]Yang[normal]: Nous arrivons tard...[new] -[bold]Giotto[normal]: Mais le cristal de ce château -est, lui, toujours en sécurité. +[bold]Giotto[normal]: Mais le cristal de ce château est, +lui, toujours en sécurité.[new] On a pu faire battre en retraite ces... heu... trucs volants avec nos chars nains.[new] [bold]Rosa[normal]: Alors c'étaient vos chars qui combattaient les aéronefs.[new] -[bold]Giotto[normal]: Oh, comme ça vous appelez -ces choses aéronefs... -Wow, le monde du dessus a des trucs -de ce genre![new] -Nous sommes fiers de nos chars, mais -ils nous touchaient salement avec leurs +[bold]Giotto[normal]: Oh, comme ça vous appelez ces +choses aéronefs... +Wow, le monde du dessus a des trucs de +ce genre![new] +Nous sommes fiers de nos chars, mais ils +nous touchaient salement avec leurs attaques. Nous aiderez-vous avec votre aéronef?[new] [bold]Cid[normal]: J'ai rien contre, mais après @@ -1599,31 +1590,34 @@ On ne va pas en tirer grand chose.[end] [bold]Caïn[normal]: Ça ne veut pas s'ouvrir![new] «Yo-ho-ho-ho-!»[end] -«Nous sommes les joyeuses Calcabrina! Poupées effrayantes mais mignonnes! Bandes d'idiots! Vous venez ici si naïvement! On va vous battre et offrir vos têtes au seigneur Golbez en cadeau! Kya-ho-ho-ho!»[end] +«Nous sommes les joyeuses Calcabrina! +Poupées effrayantes mais mignonnes! +Bandes d'idiots! Vous venez ici si +naïvement! On va vous battre et offrir vos +têtes au seigneur Golbez en cadeau! +Kya-ho-ho-ho!»[end] [bold]Cecil[normal]: Quoi!?[new] «Cela faisait longtemps...»[end] [bold]Cecil[normal]: Golbez..![new] -[bold]Golbez[normal]: L'autre jour, vous m'avez -bien aidé. +[bold]Golbez[normal]: L'autre jour, vous m'avez bien +aidé. Mais celui qui utilisait Météore n'est plus de ce monde maintenant.[new] En remerciement de l'autre fois, je vais vous dire pourquoi je rassemble les cristaux.[new] -Lumière et ténèbres réunies... 8 -cristaux... +Lumière et ténèbres réunies... 8 cristaux... C'est la clé pour faire revivre la Tour de Babel, le chemin scellé vers la Lune.[new] -On dit qu'il y a sur la Lune un pouvoir -qui dépasse notre imagination. -Avec ce cristal, j'en ai maintenant -sept...[new] -Il n'en reste plus qu'un. +On dit qu'il y a sur la Lune un pouvoir qui +dépasse notre imagination. +Avec ce cristal, j'en ai maintenant sept... +Il n'en reste plus qu'un.[new] C'est aussi grâce à vous. Je me dois de vous remercier pour cela. -Prenez ceci![new] +Prenez ceci! C'est mon dernier cadeau![end] [bold]Cecil[normal]: On l'a vaincu! @@ -1639,26 +1633,25 @@ emmené dans le Monde Fantôme.[new] [bold]Rydia[normal]: C'est le monde où vivent les Bêtes Fantômes. Là-bas, elles sont devenues mes amies.[new] -Je ne peux plus utiliser la magie -blanche, mais en contrepartie, mes -pouvoirs d'invocation et de magie noire -se sont développés![new] +Je ne peux plus utiliser la magie blanche, +mais en contrepartie, mes pouvoirs +d'invocation et de magie noire se sont +développés![new] Mais dans le Monde Fantôme, le temps s'écoule différemment...[new] -[bold]Rosa[normal]: Et c'est pourquoi tu as -grandi si vite?[new] +[bold]Rosa[normal]: Et c'est pourquoi tu as grandi +si vite?[new] [bold]Caïn[normal]: Cecil, qui est cette enfant?[new] [bold]Cecil[normal]: C'est Rydia, du village de Mist.[new] [bold]Caïn[normal]: Cette enfant!?[new] [bold]Yang[normal]: Quelle surprise...[new] -[bold]Cecil[normal]: Mais pourquoi nous -aides-tu...? +[bold]Cecil[normal]: Mais pourquoi nous aides-tu...? J'ai tué ta mère...[new] [bold]Rydia[normal]: Ne dis rien! -La Reine du Monde Fantôme m'a dit -qu'un destin bien plus grand était en +La Reine du Monde Fantôme m'a dit qu'un +destin bien plus grand était en mouvement...[new] Que nous devons nous dresser contre lui...[new] @@ -1674,8 +1667,8 @@ Rydia a rejoint l'équipe![music][0x29][delay][0x28][end] [bold]Edge[normal]: Ouais! On va tous y aller et rentrer dans leur base![new] -[bold]Rydia[normal]: Ça c'est bien trouvé! [0xfa]Le -ninja Edge a rejoint l'équipe![music][0x29][delay][0x28][end] +[bold]Rydia[normal]: Ça c'est bien trouvé! [0xfa]Le ninja +Edge a rejoint l'équipe![music][0x29][delay][0x28][end] [bold]Cid[normal]: Maintenant, vous pourrez voler sans vous soucier de la lave![new] @@ -1696,14 +1689,14 @@ Fini de rire... Il est temps de nous dire adieu.[new] Adieu...![end] -«Pile poil! Halàlà, j'ai horreur d'être aussi bon!»[new] +«Pile poil! Halàlà, j'ai horreur d'être aussi +bon!»[new] [bold]Rosa[normal]: Cid![end] [bold]Cid[normal]: Euh? Où est Yang?[new] [bold]Rosa[normal]: Il...[new] -[bold]Cecil[normal]: Pour détruire le super -canon...[new] +[bold]Cecil[normal]: Pour détruire le super canon...[new] [bold]Cid[normal]: Je vois... Yang...[new] [bold]Rydia[normal]: Sniff...[new] @@ -1718,12 +1711,12 @@ Prends les commandes, Cecil![end] [bold]Cecil[normal]: Où vas-tu?![end] [bold]Cid[normal]: Quand l'Entreprise arrivera à -la surface, je scellerai le trou avec -cette bombe![end] +la surface, je scellerai le trou avec cette +bombe![end] [bold]Cid[normal]: Golbez! -L'ingénieur aéronautique Cid va -te montrer son chef-d'uvre![end] +L'ingénieur aéronautique Cid va te +montrer son chef-d'uvre![end] [bold]Cid[normal]: Écoutez! Magnez-vous, allez à Baron![end] @@ -1746,14 +1739,17 @@ Pendant que tu pilotes l'Entreprise, presse le bouton d'action au-dessus de l'aéroglisseur![new] Maintenant tu peux aller à la grotte -d'Eblana près de la Tour de Babel![new] +d'Eblana près de la Tour de Babel! Dépose l'aéroglisseur dans les eaux peu -profondes du continent et monte à -bord![end] +profondes du continent et monte à bord![end] [bold]Cecil[normal]: Pour être franc, Cid est...[new] -«Trop énergique et embêtant, pas vrai? Soyez assurés que ce n'est pas quelqu'un qui mourrait facilement! Bon, on a des montagnes de travail qui nous attendent! Bon courage!»[end] +«Trop énergique et embêtant, pas vrai? +Soyez assurés que ce n'est pas quelqu'un +qui mourrait facilement! Bon, on a des +montagnes de travail qui nous attendent! +Bon courage!»[end] [bold]Homme[normal]: Je t'ai enfin trouvé, Rubicante! J'attendais ce jour depuis longtemps![new] @@ -1763,8 +1759,7 @@ présentés?[new] maître ninja Edge![new] [bold]Rubicante[normal]: Eblana? Qu'est-ce que c'est?[new] -[bold]Edge[normal]: Demande donc à ta -conscience![end] +[bold]Edge[normal]: Demande donc à ta conscience![end] [bold]Cecil[normal]: Ça va?[new] [bold]Edge[normal]: Quelle honte... que moi, je @@ -1796,11 +1791,10 @@ Tout le monde... tout le monde![new] [bold]Cecil[normal]: ...L'adversaire est le plus puissant des Quatre Élémentaux. -On ne sait même pas si on a une -chance![new] +On ne sait même pas si on a une chance![new] Mais nous devons récupérer les cristaux![new] -[bold]Edge[normal]: ...Une si jolie fille qui pleure... -je n'ai pas le choix... +[bold]Edge[normal]: ...Une si jolie fille qui pleure... je +n'ai pas le choix... Bon, unissons nos forces![new] [bold]Caïn[normal]: Franchement, ce prince et sa grande gueule malgré son état... @@ -1814,8 +1808,8 @@ Ils gagnent du terrain sur nous![end] [bold]Edge[normal]: Papa! Maman![end] -[bold]Reine Eblana[normal]: Je suis si contente de -te voir ici![new] +[bold]Reine Eblana[normal]: Je suis si contente de te +voir ici![new] [bold]Edge[normal]: Dieu merci, tu vas bien! Oh, maman... J'étais si inquiet...[new] @@ -1865,15 +1859,15 @@ Vous êtes condamnés à rester éternellement faibles.[new] «Humain»[new] ...c'est ça? -Je vais te montrer cette chose[new] +Je vais te montrer cette chose «humaine»[new] ... ...qu'est la rage![music][0xb] [0xfa]La rage a révélé les pouvoirs cachés de Edge! [0xfa]Edge a appris Suiton et Raijin! -[bold]Rubicante[normal]: Oh...ainsi, la rage donne -de la force aux humains... -Mais la glace elle-même ne peut -pénétrer mon manteau de flammes![end] +[bold]Rubicante[normal]: Oh...ainsi, la rage donne de la +force aux humains... +Mais la glace elle-même ne peut pénétrer +mon manteau de flammes![end] [bold]Rubicante[normal]: Maintenant je vais vous soigner! @@ -1882,10 +1876,9 @@ Combattez de toutes vos forces![end] [bold]Rubicante[normal]: Oh... je vois... Individuellement, les humains sont faibles, mais ensemble... ils sont puissants![new] -À présent, je comprends mieux -comment vous avez battu le seigneur -Golbez... -Je vous salue, braves guerriers![new] +À présent, je comprends mieux comment +vous avez battu le seigneur Golbez... +Je vous salue, braves guerriers! Adieu...[end] Jeune maître![end] @@ -1897,8 +1890,8 @@ combattrons! Où est Rubicante?![end] [bold]Edge[normal]: C'est fini![new] -[bold]Chambellan[normal]: Ah, comme on s'y -attendait de notre jeune maître![new] +[bold]Chambellan[normal]: Ah, comme on s'y attendait +de notre jeune maître![new] [bold]Edge[normal]: C'est grâce à eux![new] [bold]Chambellan[normal]: Vous tous![end] @@ -1909,8 +1902,8 @@ d'aller sur la Lune![new] [bold]Edge[normal]: Cette Lune-là? Mais pourquoi?[new] [bold]Cecil[normal]: Il paraît qu'il y aurait sur la -Lune quelque chose capable de détruire -le monde.[new] +Lune quelque chose capable de détruire le +monde.[new] [bold]Rydia[normal]: Nous devons l'arrêter![new] [bold]Edge[normal]: Golbez! Tout ça à cause de lui... @@ -1920,16 +1913,16 @@ reconstruire le château![end] [bold]Edge[normal]: Ce n'est pas qu'Eblana! Le monde entier est en danger! -Moi aussi, je vais écraser ce Golbez -de mes propres mains![new] +Moi aussi, je vais écraser ce Golbez de +mes propres mains![new] [bold]Chambellan[normal]: Faites bien attention à vous...![new] [bold]Edge[normal]: Je sais! Allez, laissez-moi la suite![new] [bold]Chambellan[normal]: Compris! Je m'occupe de la maison! -Tout le monde, je vous confie notre -jeune maître![new] +Tout le monde, je vous confie notre jeune +maître![new] Allez, on rentre![end] [bold]Tous[normal]: Jeune maître! @@ -1941,17 +1934,15 @@ Que la bonne fortune soit avec vous![new] jusqu'au monde souterrain...[end] [bold]Tellah[normal]: Je suis Tellah! -Je me rendais à Damcyan, mais plus -haut dans le lac, il y a un énorme -monstre.[new] +Je me rendais à Damcyan, mais plus haut +dans le lac, il y a un énorme monstre.[new] Ma magie n'est pas assez forte pour le -battre seul, mais avec votre lame noire... -je devrais pouvoir le vaincre. !? +battre seul, mais avec votre lame noire... je +devrais pouvoir le vaincre. !? Oh![new] Cette fille est une invocatrice, hein? Je sens qu'elle a du talent. -À trois, nous devrions pouvoir y -arriver...[new] +À trois, nous devrions pouvoir y arriver...[new] [bold]Cecil[normal]: On est aussi en route pour Damcyan![new] [bold]Tellah[normal]: Bien, alors c'est d'accord! @@ -2030,34 +2021,33 @@ Demandons aussi à Léviathan et aux autres de nous prêter leur force![end] [bold]Rydia[normal]: C'est ici que j'ai vécu... -Voyons si nous pouvons trouver -quelque chose d'utile par ici.[end] +Voyons si nous pouvons trouver quelque +chose d'utile par ici.[end] [bold]Rydia[normal]: Reine Asura![new] -[bold]Asura[normal]: Ça faisait longtemps, -Rydia...[new] +[bold]Asura[normal]: Ça faisait longtemps, Rydia...[new] [bold]Rydia[normal]: Nous avons besoin de vos pouvoirs![new] [bold]Asura[normal]: Alors je voudrais vous aider... mais je dois d'abord évaluer votre force. -C'est la loi du Monde des Bêtes -Fantômes.[new] -Avez-vous le courage de me défier et -la force de me vaincre?[end] +C'est la loi du Monde des Bêtes Fantômes.[new] +Avez-vous le courage de me défier et la +force de me vaincre?[end] Rydia... -Bien que vous soyez les premiers à -avoir vaincu Asura, la force ne vous -suffira pas pour vous opposer au mal.[new] +Bien que vous soyez les premiers à avoir +vaincu Asura, la force ne vous suffira pas +pour vous opposer au mal.[new] Vous devez posséder une puissante -volonté pour vous guider sur la voie de -la lumière...[new] +volonté pour vous guider sur la voie de la +lumière...[new] Mon esprit a traversé les méandres du temps. Que va-tu répondre? Veux-tu te mesurer à moi?[end] -«Reviens à moi... Caïn... Rapporte-moi le cristal et reviens à moi...»[new] +«Reviens à moi... Caïn... Rapporte-moi +le cristal et reviens à moi...»[new] [bold]Cecil[normal]: Golbez![end] [bold]Cecil[normal]: Ooh! [0xfa]Caïn a volé le @@ -2095,9 +2085,10 @@ Ont été entendues![end] Le légendaire vaisseau de lumière... Le vaisseau céleste![end] -[bold]Ancien[normal]: Pendant ma prière, j'ai -entendu une voix chaleureuse.[new] -«Venez sur la Lune... Il y a ceux qui vous attendent sur la Lune!»[new] +[bold]Ancien[normal]: Pendant ma prière, j'ai entendu +une voix chaleureuse.[new] +«Venez sur la Lune... Il y a ceux qui vous +attendent sur la Lune!»[new] [bold]Cecil[normal]: Mais comment!?[end] Soyez maudits! @@ -2109,9 +2100,9 @@ Au seigneur Golbez![end] [bold]Edge[normal]: Merde... Bon sang![end] -[bold]Rubicante[normal]: Tu es effectivement -assez fort pour avoir confiance... mais tu -ne peux pas encore m'égaler. +[bold]Rubicante[normal]: Tu es effectivement assez +fort pour avoir confiance... mais tu ne +peux pas encore m'égaler. Va perfectionner tes talents![new] Je serai ton adversaire quand tu veux![end] @@ -2148,12 +2139,11 @@ cristaux?[new] [bold]Cecil[normal]: Pour être franc...[new] [bold]Giotto[normal]: Je vois... Afin d'avoir le dernier cristal, Golbez -doit briser le sceau de la grotte située -au sud-ouest.[new] -Ce n'est qu'une question de temps -avant qu'il n'y parvienne. -Je veux que vous preniez le cristal -avant.[new] +doit briser le sceau de la grotte située au +sud-ouest.[new] +Ce n'est qu'une question de temps avant +qu'il n'y parvienne. +Je veux que vous preniez le cristal avant. Luca![end] [bold]Cecil[normal]: Cid...[new] @@ -2182,12 +2172,11 @@ occuper d'un vieux comme moi![new] [bold]Cecil[normal]: Merci... Cid![end] -[0xfa]Née de la bouche d'un dragon, -[0xfa]s'élevant dans les cieux [0xfa]avec Lumière et -Obscurité, [0xfa]une promesse endormie -[0xfa]s'éveillera. [0xfa]Voilée [0xfa]par la lumière [0xfa]de -l'éternité, [0xfa]La Terre Mère sera bénie -[0xfa]avec clémence et salut.[end] +[0xfa]Née de la bouche d'un dragon, [0xfa]s'élevant +dans les cieux [0xfa]avec Lumière et Obscurité, +[0xfa]une promesse endormie [0xfa]s'éveillera. [0xfa]Voilée +[0xfa]par la lumière [0xfa]de l'éternité, [0xfa]La Terre Mère +sera bénie [0xfa]avec clémence et salut.[end] [bold]Palom[normal]: Ce vieux a appris Météor![new] [bold]Ancien[normal]: Météor...! @@ -2201,8 +2190,7 @@ Je le vaincrai avec Météor![new] Se battre avec haine détruit l'âme! Et dans ton état, Météor est trop dangereux![new] -[bold]Tellah[normal]: Même si cela doit me -détruire! +[bold]Tellah[normal]: Même si cela doit me détruire! Je ne peux pardonner à ce monstre![new] [bold]Ancien[normal]: Comme je m'y attendais. Tu n'as pas changé.[new] @@ -2210,14 +2198,14 @@ Tu n'as pas changé.[new] [bold]Ancien[normal]: Mais Cecil est devenu Paladin. Si vous unissez vos forces...![new] -[bold]Cecil[normal]: Mais pour affronter -Golbez, nous devons retourner à -Baron et prendre un aéronef...[new] +[bold]Cecil[normal]: Mais pour affronter Golbez, +nous devons retourner à Baron et prendre +un aéronef...[new] [bold]Ancien[normal]: Compris... Je vais briser le sceau de la Route du Démon![new] -En tant que Paladin, tu peux traverser -la Route du Démon! +En tant que Paladin, tu peux traverser la +Route du Démon! Va à Baron![new] J'entrerai dans la Tour des Prières et prierai pour vous... @@ -2263,8 +2251,7 @@ La ferme![end] Empereurs. Mais il a tous les cristaux sauf un...[new] [bold]Rosa[normal]: Il est caché dans une grotte -au sud-ouest, de l'autre côté du -magma...[new] +au sud-ouest, de l'autre côté du magma...[new] [bold]Caïn[normal]: On a piqué un aéronef à l'ennemi, mais il n'a pas les modifications de l'Entreprise.[new] @@ -2295,10 +2282,10 @@ Mais merde![end] [bold]Cecil[normal]: Le mur![new] [bold]Rydia[normal]: Il bouge![new] -[bold]Caïn[normal]: Comme on pouvait s'y -attendre de la grotte scellée - même -après avoir pris le cristal, on ne peut -pas se sentir en sécurité![new] +[bold]Caïn[normal]: Comme on pouvait s'y attendre +de la grotte scellée - même après avoir +pris le cristal, on ne peut pas se sentir en +sécurité![new] [bold]Edge[normal]: Alors on va le démolir![end] [bold]Rydia[normal]: On a réussi![new] @@ -2310,16 +2297,16 @@ pas se sentir en sécurité![new] Vous revoilà! Le dernier cristal...[end] -[bold]Cecil[normal]: Nous n'avons pas pu -protéger le cristal...[new] +[bold]Cecil[normal]: Nous n'avons pas pu protéger +le cristal...[new] [bold]Giotto[normal]: Quoi!? Il les a tous![new] Nous n'avons plus d'espoir... à moins que la légende du vaisseau magique ne soit vraie...[new] [bold]Cecil[normal]: Vaisseau magique!?[music][0x0][new] -[bold]Giotto[normal]: Un immense vaisseau qui -existait dans un lointain passé. +[bold]Giotto[normal]: Un immense vaisseau qui existait +dans un lointain passé. Il y a cette légende...[new] «Née de la bouche d'un dragon»[new] ... @@ -2334,8 +2321,8 @@ temple des prières et continue de prier.[new] [bold]Giotto[normal]: Se pourrait-il que cette personne...[new] [bold]Cecil[normal]: ?[new] -[bold]Giotto[normal]: Essaie de ressusciter le -vaisseau magique? +[bold]Giotto[normal]: Essaie de ressusciter le vaisseau +magique? Non! C'est notre seul espoir![new] Mysidia! @@ -2348,12 +2335,11 @@ Babel![end] «Je vais m'en occuper!»[end] -[bold]Cecil[normal]: ...Cette lumière m'a appelé -fils. +[bold]Cecil[normal]: ...Cette lumière m'a appelé fils. Qu'était cette lumière?[new] [bold]Ancien[normal]: Je ne sais pas ce qu'était la -lumière sur la Montagne de l'Épreuve, ni -ce que signifie la légende.[new] +lumière sur la Montagne de l'Épreuve, ni ce +que signifie la légende.[new] Mais nous, Mythidiens devons prier pour cette légende. Prier pour celui qui possède la Lumière @@ -2365,8 +2351,7 @@ proue du Faucon pour percer la roche qui bloque le passage vers la surface![new] [bold]Rosa[normal]: Tes blessures vont mieux?[new] [bold]Cid[normal]: Ce n'est pas le moment de -s'inquiéter des blessures d'un vieil -homme![new] +s'inquiéter des blessures d'un vieil homme![new] [bold]Edge[normal]: Tu peux vraiment le faire?[new] [bold]Cid[normal]: Pour l'ingénieur aéronautique Cid, le mot[new] @@ -2377,18 +2362,18 @@ n'existe pas![end] [bold]Porom[normal]: Si vous voulez jouer la comédie, faites-le un peu mieux![new] [bold]Cecil[normal]: Toi aussi, Golbez t'a...[new] -[bold]Beigan[normal]: Je vous prie d'arrêter de -parler ainsi... -Cette personne m'a donné quelque -chose de merveilleux.[new] +[bold]Beigan[normal]: Je vous prie d'arrêter de parler +ainsi... +Cette personne m'a donné quelque chose +de merveilleux.[new] Un pouvoir si magnifique![end] Vous avez fait de Léviathan votre allié. Mais cela aurait pu se faire sans le pouvoir de la Lumière.[new] Le jugement final pour savoir si la vraie -Lumière réside en vous... sera rendu par -le Dieu des Bêtes Fantômes... +Lumière réside en vous... sera rendu par le +Dieu des Bêtes Fantômes... Bahamut![end] [0xfa]Rydia a appris Bahamut![music][0x29][delay][0x28][end] @@ -2406,18 +2391,18 @@ inébranlable![new] [bold]Cecil[normal]: J'ai entendu dire que Cid a été capturé... c'est vrai?[new] [bold]Beigan[normal]: Quelques gardes et moi avons -essayé de le sauver, mais hélas, je suis -le seul survivant...[new] +essayé de le sauver, mais hélas, je suis le +seul survivant...[new] [bold]Cecil[normal]: Je vois... Alors joins-toi à nous! À six, on a nos chances![new] -[bold]Beigan[normal]: Oui, Cecil! [0xfa]Le capitaine -des gardes, [0xfa]Beigan, a rejoint l'équipe! [music][0x29][delay][0x28][end] +[bold]Beigan[normal]: Oui, Cecil! [0xfa]Le capitaine des +gardes, [0xfa]Beigan, a rejoint l'équipe! [music][0x29][delay][0x28][end] [bold]Cid[normal]: Bien! Au boulot![end] -[bold]Cecil[normal]: Mon cur bat la chamade...![end] +[bold]Cecil[normal]: Mon cœur bat la chamade...![end] [bold]Ancien[normal]: Va à Baron par la Route du Démon à l'est de cette ville. @@ -2451,10 +2436,10 @@ Je ne sais pas si c'est un présage...[new] [bold]Cecil[normal]: Oui, allons-y.[end] [bold]Soldat[normal]: Oui, mon capitaine![new] -[bold]Soldat[normal]: Il y a de plus en plus de -monstres ces derniers temps...[new] -[bold]Soldat[normal]: Mais il y en a vraiment trop, -à présent...[new] +[bold]Soldat[normal]: Il y a de plus en plus de monstres +ces derniers temps...[new] +[bold]Soldat[normal]: Mais il y en a vraiment trop, à +présent...[new] [bold]Cecil[normal]: Est-ce qu'il se passerait... quelque chose?[end] @@ -2462,9 +2447,10 @@ quelque chose?[end] «Vous êtes de Baron, hein...»[new] [bold]Caïn[normal]: Qui est là?[music][0x2d][new] -«Partez maintenant et il ne vous fait aucun mal...»[new] +«Partez maintenant et il ne vous fait +aucun mal...»[new] [bold]Caïn[normal]: Montre-toi![new] -«Vous voulez vraiment continuer?»[end] +«Vous voulez vraiment continuer?»[close_window][end] [bold]Edward[normal]: Cecil... Rosa veut être avec vous.[new] @@ -2474,8 +2460,8 @@ Mais il est tard. On part demain matin.[new] Pour le moment, on va se coucher.[new] [bold]Rosa[normal]: Cecil... -Merci. [0xfa]Le mage blanc Rosa a -rejoint l'équipe![end] +Merci. [0xfa]Le mage blanc Rosa a rejoint +l'équipe![end] [bold]Rosa[normal]: Je vais bien. Et je suis un mage blanc. @@ -2494,17 +2480,16 @@ Je ne serai pas un fardeau![new] J'en ai bien l'intention. Mais contre TOI, Cecil![new] [bold]Cecil[normal]: Caïn!?[new] -[bold]Caïn[normal]: Un combat d'homme à -homme, Cecil![new] +[bold]Caïn[normal]: Un combat d'homme à homme, +Cecil![new] [bold]Cecil[normal]: Caïn?[new] [bold]Caïn[normal]: Tue-moi si tu peux![end] [bold]Yang[normal]: Cecil! -Maintenant, c'est à nous de nous -battre pour toi.[new] -Nous devons discuter d'un plan -d'attaque, mais tout d'abord il faut nous -reposer.[new] +Maintenant, c'est à nous de nous battre +pour toi.[new] +Nous devons discuter d'un plan d'attaque, +mais tout d'abord il faut nous reposer.[new] [bold]Cecil[normal]: Merci, Yang...[end] Bam![end] @@ -2555,10 +2540,11 @@ Ma danse![end] [bold]Cecil[normal]: J'ai sommeil tout à coup...[end] -«Fufufu... Votre entraînement est insuffisant.»[end] +«Fufufu... Votre entraînement est +insuffisant.»[end] -[bold]Palom[normal]: Je le sais même sans qu'on -me le dise![end] +[bold]Palom[normal]: Je le sais même sans qu'on me +le dise![end] [bold]Porom[normal]: Palom! L'Ancien dit qu'il ne faut pas être @@ -2572,8 +2558,7 @@ pour ton ancien ami... Mais je lui ai envoyé Scarmiglione...[new] Scarmiglione est un des quatre Empereurs des Éléments. -Il nous a promis un divertissant -spectacle.[new] +Il nous a promis un divertissant spectacle. Qu'en penses-tu, Rosa?[end] [bold]Caïn[normal]: Oui, maître![new] @@ -2585,12 +2570,11 @@ Fais attention![end] [bold]Tellah[normal]: Cecil![end] [bold]Porom[normal]: Mais tais-toi donc![new] -[bold]Tellah[normal]: Cecil, pourquoi -êtes-vous venu ici?[new] -[bold]Cecil[normal]: Je suis venu pour être -paladin. -Je ne peux pas vaincre Golbez avec -la lame noire...[new] +[bold]Tellah[normal]: Cecil, pourquoi êtes-vous +venu ici?[new] +[bold]Cecil[normal]: Je suis venu pour être paladin. +Je ne peux pas vaincre Golbez avec la +lame noire... Je dois laisser mon passé derrière moi...[end] [bold]Tellah[normal]: Golbez est à l'origine de @@ -2600,8 +2584,8 @@ tout le mal![end] C'est bien ce que je sentais, il doit y avoir un pouvoir mystérieux caché dans cette montagne![new] -Si vous cherchez à contrer Golbez, -je me joins à vous! [0xfa]Le sage Tellah a +Si vous cherchez à contrer Golbez, je +me joins à vous! [0xfa]Le sage Tellah a rejoint l'équipe![music][0x29][delay][0x28][end] [bold]Scarmiglione[normal]: GRRRR-BAAAH![end] @@ -2618,8 +2602,7 @@ Qui es-tu?[end] [bold]Tellah[normal]: !? Mé... ...téor?[new] Cette lumière m'a donné l'ultime magie -noire, Météor! [0xfa]Tellah apprend -Météor![music][0x29][delay][0x28][end] +noire, Météor! [0xfa]Tellah apprend Météor![music][0x29][delay][0x28][end] [bold]Palom[normal]: Hé, tiens bon![end] @@ -2650,8 +2633,7 @@ Rosa, t'en fais pas![end] Où est Rosa?[new] [bold]Cecil[normal]: Il s'agit d'un échange avec le cristal de la Terre de Troia... -Mais le cristal a été volé par l'Elfe -Noir...[end] +Mais le cristal a été volé par l'Elfe Noir...[end] [bold]Edward[normal]: Cecil, prenez ça...[new] [bold]Cecil[normal]: C'est quoi?[new] @@ -2680,8 +2662,7 @@ idiot! Ne nous meurs pas dessus![new] [bold]Yang[normal]: Maître Tellah... Il est...[new] -[bold]Cid[normal]: Repose en paix... avec ta -fille...[end] +[bold]Cid[normal]: Repose en paix... avec ta fille...[end] [bold]Caïn[normal]: ...Cecil! Je... je suis désolé...[new] @@ -2734,8 +2715,8 @@ quelqu'un![new] [bold]Cid[normal]: N'est-ce pas, hein? On part demain.[new] Je ne peux pas chercher d'entrées de -mondes d'en dessous sans une bonne -nuit de sommeil![end] +mondes d'en dessous sans une bonne nuit +de sommeil![end] [bold]Cecil[normal]: Mais... pourquoi Golbez ne m'a-t-il pas tué...? @@ -2743,37 +2724,49 @@ Qui est-il..?[end] [bold]Rosa[normal]: Qu'y a-t-il?[end] -[0xfa]Ainsi, le chevalier noir [0xfa]Cecil perdit -sa place [0xfa]de capitaine des Ailes Rouges. -[0xfa]Lui et le chevalier dragon [0xfa]Caïn -reçurent l'ordre [0xfa]de se rendre à Mist, [0xfa]un -village provincial situé [0xfa]par-delà les -montagnes [0xfa]dans une vallée recouverte -[0xfa]par un épais brouillard... [0xfa]Les aéronefs... -[0xfa]Le vol fut longtemps [0xfa]un rêve -inaccessible [0xfa]de l'humanité. [0xfa]Ces vaisseaux -donnèrent [0xfa]aux hommes le pouvoir [0xfa]de -s'élever dans les cieux. [0xfa]Très vite, [0xfa]comme -toute création [0xfa]humaine, il devint un [0xfa]outil -de la cupidité. [0xfa]Le pays de Baron devint -[0xfa]la plus forte puissance [0xfa]militaire au -monde [0xfa]par leurs aéronefs, [0xfa]les Ailes -Rouges... [0xfa]Mais pourquoi un pays aussi -[0xfa]puissant recherche-t-il [0xfa]les cristaux? -[0xfa]Quel pouvoir recèlent-ils? [0xfa]Pourquoi -l'humanité [0xfa]corrompt-elle chaque -[0xfa]réalisation de ses rêves? [0xfa]Et pourquoi les -monstres [0xfa]se font-ils toujours plus -nombreux, [0xfa]même en plein jour? [0xfa]Les -cristaux luisaient [0xfa]silencieusement...[end] +[force_book]Ainsi, le chevalier noir +Cecil perdit sa place de +capitaine des Ailes Rouges.[new] +Lui et le chevalier dragon +Caïn reçurent l'ordre de se +rendre à Mist, un village +provincial situé par-delà les +montagnes dans une vallée +recouverte par un épais +brouillard...[new] +Les aéronefs... +Le vol fut longtemps un rêve +inaccessible de l'humanité.[new] +Ces vaisseaux donnèrent aux +hommes le pouvoir de s'élever +dans les cieux.[new] +Très vite, comme toute +création humaine, il devint un +outil de la cupidité.[new] +Le pays de Baron devint la +plus forte puissance militaire +au monde par leurs aéronefs, +les Ailes Rouges...[new] +Mais pourquoi un pays aussi +puissant recherche-t-il les +cristaux? +Quel pouvoir recèlent-ils?[new] +Pourquoi l'humanité +corrompt-elle chaque +réalisation de ses rêves?[new] +Et pourquoi les monstres se +font-ils toujours plus +nombreux, même en plein jour?[new] +Les cristaux luisaient +silencieusement...[end] [bold]Cecil[normal]: Rosa![end] [bold]Giotto[normal]: Que vous faut-il pour vos réparations?[new] [bold]Cid[normal]: Je peux faire quelques -réparations provisoires avec les -matériaux disponibles ici...[new] +réparations provisoires avec les matériaux +disponibles ici...[new] Mais le corps de l'aéronef ne résistera pas aux flammes de votre monde. Je dois retourner à la surface et @@ -2783,7 +2776,7 @@ Bon, ben, j'y vais![end] [0xfa]Tu as le cristal d'Obscurité![music][0x29][delay][0x24][end] [bold]Cecil[normal]: Mais...[new] -[bold]Palom[normal]: Tu nous as vus à l'uvre, non?[new] +[bold]Palom[normal]: Tu nous as vus à l'œuvre, non?[new] [bold]Porom[normal]: Oui![new] [bold]Tellah[normal]: Pas d'inquiétude. Je suis avec vous![new] @@ -2795,12 +2788,12 @@ Tu nous as dit de l'aider![new] [bold]Porom[normal]: S'il vous plaît, laissez-nous aussi y aller...[new] [bold]Ancien[normal]: Bien... -La Montagne de l'Épreuve t'a accepté -et tu en es revenu vivant.[new] +La Montagne de l'Épreuve t'a accepté et +tu en es revenu vivant.[new] Tu dois avoir une destinée bien plus importante que je ne peux l'entrevoir... -Je voudrais bien vous accompagner, -mais je ne peux quitter Mythidia.[new] +Je voudrais bien vous accompagner, mais +je ne peux quitter Mythidia.[new] Cecil, Tellah... Prenez soin de ces deux enfants pour moi![end] @@ -2828,8 +2821,7 @@ Nous devons vaincre Golbez!![new] [bold]Caïn[normal]: Tu ne peux pas les semer!?[new] [bold]Cid[normal]: Merde, cet aéronef devrait être plus rapide que les leurs! -Ils ont dû aussi modifier les Ailes -Rouges![new] +Ils ont dû aussi modifier les Ailes Rouges! Qui est-ce qu'ils ont pris pour faire ça?[end] [bold]Rydia[normal]: Ils approchent![new] @@ -2841,8 +2833,7 @@ Je voulais voir vos enfants, Rosa... Cecil...[new] Mais Yang va être seul, ça ne va pas... -Allez à Baron et parlez à mes -apprentis![end] +Allez à Baron et parlez à mes apprentis![end] [bold]Cecil[normal]: Cid![new] [bold]Rydia[normal]: Grand-père![end] @@ -2865,16 +2856,15 @@ combattre avec vous![new] Ouvre la porte!![new] [bold]Yang[normal]: Aaaagh![end] -[bold]Porom[normal]: Ben oui, quoi, c'est un -paladin![new] +[bold]Porom[normal]: Ben oui, quoi, c'est un paladin![new] [bold]Palom[normal]: Même si je ne le croyais pas possible.[new] [bold]Cecil[normal]: Comment ça?[new] [bold]Ancien[normal]: J'ai honte... Palom et Porom étaient chargés de t'espionner.[new] -Mais il semble que c'était inutile en fin -de compte. +Mais il semble que c'était inutile en fin de +compte. Bon travail, Palom et Porom![end] [0xfa]Rydia apprend Asura![music][0x29][delay][0x28][end] @@ -2888,8 +2878,8 @@ Tu es..!![end] [bold]Tellah[normal]: Anna! Anna![delay][0x2b][end] -[bold]Tellah[normal]: Il représentait tant que ça -pour toi..?[new] +[bold]Tellah[normal]: Il représentait tant que ça pour +toi..?[new] [bold]Anna[normal]: Père... pardonne-moi... J'aime Edward..![end] @@ -2901,8 +2891,8 @@ prince Edward a rejoint le groupe![music][0x29][delay][0x28][end] [bold]Tellah[normal]: Il est en bas![end] -[bold]Cecil[normal]: Le courant est trop fort -pour entrer![end] +[bold]Cecil[normal]: Le courant est trop fort pour +entrer![end] Vous avez votre carte de membre?[end] @@ -2910,8 +2900,7 @@ pour entrer![end] [bold]Cecil[normal]: Yang![music][0x2a][delay][0x30][end] -[0xfa]Tu as trouvé le Livre de la -Connaissance![end] +[0xfa]Tu as trouvé le Livre de la Connaissance![end] [0xfa]Tu as trouvé un magazine coquin![end] @@ -2937,8 +2926,8 @@ Tu veux voir le roi? Je ne suis pas aussi pathétique que Scarmiglione![new] C'est un miracle qu'un cadavre animé -bouffe-charognes comme lui ait été l'un -de nous quatre! +bouffe-charognes comme lui ait été l'un de +nous quatre! Hé hé hé hé hé![new] [bold]Cecil[normal]: Alors tu es...![end] @@ -2971,11 +2960,14 @@ On est touché! On va s'écraser! Accrochez-vous![end] -«Mort à ceux qui convoitent cette Lance Sacrée!»[end] +«Mort à ceux qui convoitent cette Lance +Sacrée!»[end] -«Tu n'obtiendras jamais la sainte protection de ces Rubans!»[end] +«Tu n'obtiendras jamais la sainte +protection de ces Rubans!»[end] -«Seigneur Zémus abhorre le pouvoir de cette épée. Il ne doit pas être libéré!»[end] +«Seigneur Zémus abhorre le pouvoir de +cette épée. Il ne doit pas être libéré!»[end] [bold]Dr Lugeie[normal]: Ha Ha Ha! Je me suis toujours demandé ce qu'était @@ -2983,8 +2975,8 @@ la mort... Soyez maudits, robots et humains![new] L'au-delà est l'ultime expérience... Vous croyez avoir gagné? -Cette tour relie les deux mondes, celui -du dessus et celui du dessous...[new] +Cette tour relie les deux mondes, celui du +dessus et celui du dessous...[new] Les cristaux y ont déjà été amenés par Rubicante! Hahahahaha![new] @@ -2992,13 +2984,14 @@ Et je vais anéantir les nains avec mon super canon! Même dans la mort, je suis gagnant![end] -«Allez-y donc avant de prendre ce katana! En enfer...!»[end] +«Allez-y donc avant de prendre ce +katana! En enfer...!»[end] [bold]Yang[normal]: Ça veut donc dire qu'ils vont essayer de voler le cristal de l'air![new] [bold]Edward[normal]: Sûrement. -Damcyan a déjà été attaqué et le -cristal volé.[new] +Damcyan a déjà été attaqué et le cristal +volé.[new] [bold]Yang[normal]: !...Bon sang! Et nos forces principales qui ont été anéanties![new] diff --git a/text/fr/bank1-2.xml b/text/fr/bank1-2.xml index dc48b40..6673d44 100644 --- a/text/fr/bank1-2.xml +++ b/text/fr/bank1-2.xml @@ -1,13 +1,13 @@ Une force mystérieuse entoure ce lieu. -Tu peux utiliser une tente ou une -cabine, et sauvegarder.[end] +Tu peux utiliser une tente ou une cabine, +et sauvegarder.[end] [bold]Golbez[normal]: C'est terminé...[new] [bold]FuSoYa[normal]: Quelle tragédie... -Il avait de si fantastiques pouvoirs, mais -il était rongé par le mal...[new] +Il avait de si fantastiques pouvoirs, mais il +était rongé par le mal...[new] [bold]Edge[normal]: Yahoo!![end] [bold]FuSoYa[normal]: Oh, vous êtes venus![end] @@ -25,13 +25,13 @@ n'aurez rien à craindre! Plein gaz, les gars!![end] [bold]Edward[normal]: Cecil! -Je vais vous montrer le courage que -vous m'avez enseigné![end] +Je vais vous montrer le courage que vous +m'avez enseigné![end] -[bold]Edge[normal]: Et me voici, gonflé à bloc -pour combattre ce salaud! -Ah, bon... il ne faut pas transpirer -devant les dames.[new] +[bold]Edge[normal]: Et me voici, gonflé à bloc pour +combattre ce salaud! +Ah, bon... il ne faut pas transpirer devant +les dames.[new] [bold]Golbez[normal]: Cecil...[end] [bold]Giotto[normal]: Feu à volonté, force des chars @@ -51,17 +51,17 @@ Un travail d'intérieur![end] [bold]Palom[normal]: Hé bien, au fond, c'est un échange.[new] -[bold]Porom[normal]: Je suis désolée que nous -vous ayons trompé. +[bold]Porom[normal]: Je suis désolée que nous vous +ayons trompé. Mais nous n'avions pas le choix.[new] [bold]Cecil[normal]: Je comprends. Vu mon passé, c'était prévisible.[new] -[bold]Ancien[normal]: Mais tu as purgé la noirceur -de ton âme... et reçu la lumière sacrée. !? +[bold]Ancien[normal]: Mais tu as purgé la noirceur de +ton âme... et reçu la lumière sacrée. !? Ce n'est pas possible..! Cette épée?![new] -[bold]Cecil[normal]: La lumière de la montagne -me l'a donnée...[new] +[bold]Cecil[normal]: La lumière de la montagne me +l'a donnée...[new] [bold]Ancien[normal]: Ères de prophéties, prières, croyance... et maintenant..! Regarde! @@ -73,8 +73,7 @@ La légende de Mythidia![new] [bold]Edge[normal]: Comme si j'allais te croire! Et si tu redevenais mauvais?[end] -[bold]Caïn[normal]: ...Si c'était le cas, n'hésite -pas... +[bold]Caïn[normal]: ...Si c'était le cas, n'hésite pas... Tue-moi![end] [bold]Caïn[normal]: ...Moi aussi, je viens. @@ -124,10 +123,10 @@ Ne sais-tu donc même pas qui tu es!?[new] [bold]Golbez[normal]: ....Non... Qu'est-ce que j'ai fait?... -Seigneur... qu'est-ce que j'ai fait? -...J'étais rempli de tant de haine....[new] -[bold]FuSoYa[normal]: ...Tu as recouvré tes sens. -...Ton père...Dis-moi le nom de ton père![new] +Seigneur... qu'est-ce que j'ai fait? ...J'étais +rempli de tant de haine....[new] +[bold]FuSoYa[normal]: ...Tu as recouvré tes sens. ...Ton +père...Dis-moi le nom de ton père![new] [bold]Golbez[normal]: Mon père... KluYa...[new] [bold]Cecil[normal]: QUOI!?[new] @@ -137,8 +136,8 @@ frère de....[new] [bold]Cecil[normal]: Golbez est mon...[new] [bold]FuSoYa[normal]: Tu étais contrôlé par Zémus... Ceux de sang lunien sont sensibles aux -pouvoirs psychiques, et donc plus faciles -à contrôler...[new] +pouvoirs psychiques, et donc plus faciles à +contrôler...[new] Tu étais son pantin contre ton gré...[end] [bold]Edge[normal]: Qu'est-ce que![new] @@ -162,8 +161,7 @@ moi-même![end] [bold]FuSoYa[normal]: Attends![end] -[bold]FuSoYa[normal]: Zémus est aussi de notre -race! +[bold]FuSoYa[normal]: Zémus est aussi de notre race! Je vais venir avec toi...!![end] [bold]Golbez[normal]: Adieu, Cecil....[end] @@ -191,8 +189,8 @@ C'est mauvais, ça![new] [bold]Rosa[normal]: Caïn![new] [bold]Edge[normal]: On marche pas, cette fois![end] -[bold]Caïn[normal]: J'ai enfin repris le contrôle -de moi-même. +[bold]Caïn[normal]: J'ai enfin repris le contrôle de +moi-même. Mon esprit restait prisonnier de mes mauvaises actions...[new] Je ne peux pas vous demander de me @@ -203,27 +201,27 @@ pardonner, mais...[end] [bold]Rosa[normal]: Golbez est le frère de Cecil...[new] [bold]Cecil[normal]: ...[new] -[bold]Rosa[normal]: Golbez et Cecil ont -du sang des Luniens, une race évoluée -qui hiberne sur la lune.[new] +[bold]Rosa[normal]: Golbez et Cecil ont du +sang des Luniens, une race évoluée qui +hiberne sur la lune.[new] Un Lunien, Zémus, voulait asservir la Terre, alors il a utilisé Golbez pour rassembler les cristaux.[new] -Par ailleurs, un autre Lunien, FuSoYa, -a désenvoûté Golbez...[new] +Par ailleurs, un autre Lunien, FuSoYa, a +désenvoûté Golbez...[new] [bold]Rydia[normal]: Et alors Golbez a accompagné FuSoYa sur la lune pour anéantir Zémus.[new] [bold]Caïn[normal]: Golbez est.... le frère de Cecil..?[end] -[bold]Edge[normal]: Ah, croyez-moi, je vais aussi -y aller! +[bold]Edge[normal]: Ah, croyez-moi, je vais aussi y +aller! Entre Zémus et vous, au moins, je suis sûr d'avoir de l'action![new] -En plus, je ne vais pas rester à -regarder Zémus jouer avec la vie des -gens comme ça![new] +En plus, je ne vais pas rester à regarder +Zémus jouer avec la vie des gens comme +ça![new] [bold]Caïn[normal]: Edge...[new] [bold]Cecil[normal]: Allons-y...[end] @@ -262,9 +260,9 @@ je ne bouge pas d'un pouce.[new] [bold]Cecil[normal]: Quoi!! Rosa! C'est dangereux, là dehors![new] -[bold]Rosa[normal]: Tant que je suis auprès de -toi, quoi qu'il arrive...[music][0x13] ... non, tant que je -suis avec toi, je me fiche bien du danger![new] +[bold]Rosa[normal]: Tant que je suis auprès de toi, +quoi qu'il arrive...[music][0x13] ... non, tant que je suis +avec toi, je me fiche bien du danger![new] [bold]Cecil[normal]: Rosa...[new] [bold]Caïn[normal]: ....Allez, Cecil...[new] [bold]Edge[normal]: Ouais, laisse-la venir! @@ -312,17 +310,19 @@ Augmenté par la haine de Zémus...[end] [bold]Cecil[normal]: Zéromus....![new] [bold]Zéromus[normal]: Je... ...vais...vous...détruire...!!![end] -«....Je.... ne... périrai pas... ....Tant que...le... mal.... ...hantera...le... cœur...des...hommes... Urgh...Gyaa... Gyaaaaaaaaammmmmmm!!!!»[end] +«....Je.... ne... périrai pas... ....Tant que...le... +mal.... ...hantera...le... cur...des...hommes... +Urgh...Gyaa... Gyaaaaaaaaammmmmmm!!!!»[end] [bold]FuSoYa[normal]: Incroyable![end] -[bold]FuSoYa[normal]: Dire que vous aviez autant -de puissance.... +[bold]FuSoYa[normal]: Dire que vous aviez autant de +puissance.... La Planète Bleue a tant évolué pendant que nous dormions?[new] [bold]Edge[normal]: Ha! -Si on écoute Rydia, je pourrais -être le chaînon manquant...[end] +Si on écoute Rydia, je pourrais être +le chaînon manquant...[end] [bold]Ancien[normal]: Toi! C'est toi, le chevalier noir! @@ -335,8 +335,8 @@ Je ne pouvais me résoudre à désobéir aux ordres du Roi. Maintenant, je viens rechercher le pardon.[new] -[bold]Ancien[normal]: Même si tu t'excuses, cela ne -va pas ramener les gens que tu as +[bold]Ancien[normal]: Même si tu t'excuses, cela ne va +pas ramener les gens que tu as assassinés.[new] [bold]Cecil[normal]: ...[new] [bold]Ancien[normal]: Toutefois... @@ -344,14 +344,13 @@ Je sens une pâle lueur en toi qui n'était pas là avant.[new] Cela vaudrait peut-être la peine d'écouter ce que tu as à dire.[new] -[bold]Cecil[normal]: Je combats Golbez, -l'homme qui contrôle Baron.[new] +[bold]Cecil[normal]: Je combats Golbez, l'homme +qui contrôle Baron.[new] Quand mes amis et moi-même essayions d'empêcher le vol du cristal du vent... il a enlevé l'une des nôtres.[new] Nous étions partis la sauver, mais -Léviathan nous a attaqués, et -maintenant...[new] +Léviathan nous a attaqués, et maintenant...[new] [bold]Ancien[normal]: ...Tu as perdu tes amis... Il semble que le destin ait choisi de te faire subir cette épreuve. @@ -360,8 +359,8 @@ Tu cherches à détruire une immense noirceur... mais tant que tu te fieras à la lame noire, tu ne pourras pas vaincre le mal véritable.[new] -Ton âme est entachée par la noirceur -de tes actions... +Ton âme est entachée par la noirceur de +tes actions... Le mal est comme un cancer.[new] Il se répand, consumant entièrement l'âme. @@ -370,20 +369,18 @@ l'homme que tu poursuis...[new] Si tu souhaites changer ta pâle lueur en lumière rayonnante, alors va sur la montagne de l'Épreuve à l'est.[new] -[bold]Cecil[normal]: Mais je dois sauver mon -amie![new] -[bold]Ancien[normal]: Si tu chéris vraiment cette -amie, tu devras endurer cette épreuve... -et être baigné dans la lumière purifiante -de la rédemption au sommet...[new] +[bold]Cecil[normal]: Mais je dois sauver mon amie![new] +[bold]Ancien[normal]: Si tu chéris vraiment cette amie, +tu devras endurer cette épreuve... et être +baigné dans la lumière purifiante de la +rédemption au sommet...[new] Tu dois renoncer à ta lame moire et recevoir le pouvoir du chevalier sacré... le paladin! Sois averti, néanmoins.[new] Nombreux sont ceux qui ont tenté de devenir paladin.[new] -[bold]Cecil[normal]: Ils ont essayé et ont -échoué?[new] +[bold]Cecil[normal]: Ils ont essayé et ont échoué?[new] [bold]Ancien[normal]: Oh, non. Ils ont essayé et sont morts... Mais tu sembles porter une grande @@ -399,19 +396,17 @@ Porom![end] «Bienvenue!»[end] [bold]Cecil[normal]: Qui es-tu...?[new] -[bold]Vieil Homme[normal]: Je suis FuSoYa, -gardien du peuple endormi de la Lune, -les Luniens.[new] +[bold]Vieil Homme[normal]: Je suis FuSoYa, gardien +du peuple endormi de la Lune, les Luniens.[new] [bold]Rosa[normal]: Luniens?[new] [bold]FuSoYa[normal]: En effet. Il y a très longtemps...[new] Nous sommes le peuple d'une planète -jadis détruite, située entre la quatrième -et la cinquième planète du système -solaire.[new] +jadis détruite, située entre la quatrième et +la cinquième planète du système solaire.[new] Pendant les derniers jours de notre -monde, nous construisîmes un vaisseau -et voyageâmes vers la Planète Bleue...[new] +monde, nous construisîmes un vaisseau et +voyageâmes vers la Planète Bleue...[new] Le voyage fut long... il nous fallut hiberner pour survivre.[new] [bold]Cecil[normal]: La Planète Bleue...?[new] @@ -423,20 +418,19 @@ Alors nous créâmes une autre lune et continuâmes à dormir...[end] [bold]Edge[normal]: Une autre lune?[new] -[bold]FuSoYa[normal]: Mais l'un des nôtres refusa -de dormir...[new] +[bold]FuSoYa[normal]: Mais l'un des nôtres refusa de +dormir...[new] Il voulait purger votre planète de tout -être vivant pour pouvoir nous y -installer.[new] +être vivant pour pouvoir nous y installer.[new] [bold]Rydia[normal]: Quelle horreur...![new] [bold]FuSoYa[normal]: ...Il était un brillant mais impatient homme. -Nous tentâmes de le raisonner, mais il -ne voulut pas nous écouter.[new] +Nous tentâmes de le raisonner, mais il ne +voulut pas nous écouter.[new] Au lieu de cela, il devint amer et rancunier...[new] -Il créa la Tour de Bab-Ilu afin de donner -à l'humanité l'outil pour se détruire +Il créa la Tour de Bab-Ilu afin de donner à +l'humanité l'outil pour se détruire d'elle-même.[new] C'est alors que je forçai cet homme à dormir, mais son esprit était toujours @@ -453,8 +447,7 @@ dont l'âme est noire...[end] qu'un pantin?![new] [bold]Edge[normal]: Qui est ce type!?[new] [bold]FuSoYa[normal]: Son nom est Zémus...! -Les cristaux sont notre source -d'énergie.[new] +Les cristaux sont notre source d'énergie.[new] Zémus, ce sachant, usa de la puissance des cristaux pour mettre en marche l'ascenseur dimensionnel de la tour de @@ -465,24 +458,23 @@ l'humanité... le géant de Bab-Ilu![new] [bold]Rosa[normal]: Le[new] «chemin vers la Lune»[new] ... c'est ça...? -[bold]FuSoYa[normal]: Mais le reste des nôtres -n'est pas comme ça...[new] -Nous voulions attendre que les gens de -la Planète Bleue fussent suffisamment +[bold]FuSoYa[normal]: Mais le reste des nôtres n'est +pas comme ça...[new] +Nous voulions attendre que les gens de la +Planète Bleue fussent suffisamment avancés... pour pouvoir parler avec nous, partager nos espoirs, nos craintes, nos expériences, et nos destins.[new] Ensemble, nos peuples unis eussent tant pu faire... Nous... rêvions de ce jour...[new] -[bold]Cecil[normal]: Et le vaisseau céleste qui -nous a amenés ici?[new] +[bold]Cecil[normal]: Et le vaisseau céleste qui nous +a amenés ici?[new] [bold]FuSoYa[normal]: Il n'y a pas si longtemps, mon -frère cadet, KluYa, le construisit et -partit sur la Planète Bleue.[new] -KlûYa était passionné par votre monde -et souvent parlait d'aider votre -évolution...[new] +frère cadet, KluYa, le construisit et partit +sur la Planète Bleue.[new] +KlûYa était passionné par votre monde et +souvent parlait d'aider votre évolution...[new] Il bâtit la Route du Démon, et donna à votre peuple la technologie pour construire des aéronefs.[new] @@ -504,13 +496,12 @@ Montagne de l'Épreuve, c'était...[new] C'était l'esprit de KluYa... Je vois, à présent... tu ressembles tellement à KluYa... quand il était jeune...[new] -[bold]Cecil[normal]: Cette voix, c'était... mon -père...![new] +[bold]Cecil[normal]: Cette voix, c'était... mon père...![new] [bold]FuSoYa[normal]: KluYa t'a donné sa puissance pour combattre Zémus... Nous devons l'arrêter![new] -Pour les gens de la Lune et de la -Planète Bleue! +Pour les gens de la Lune et de la Planète +Bleue! Hâtons-nous vers la tour de Bab-Ilu![new] [bold]Edge[normal]: La tour de Bab-Ilu!? Mais elle est entourée d'une barrière![end] @@ -527,18 +518,17 @@ Zéromus...[end] [bold]Rosa[normal]: Tant qu'il y aura des curs maléfiques...[new] -[bold]FuSoYa[normal]: Chacun porte tant le bien -que le mal en son cur... exactement -comme il y a des cristaux de Lumière et -d'Obscurité...[new] +[bold]FuSoYa[normal]: Chacun porte tant le bien que +le mal en son cur... exactement comme il y +a des cristaux de Lumière et d'Obscurité...[new] Le mal jamais ne disparaîtra... mais tant que les humains continueront de se soutenir, chérissant les idéaux de vertu, de confiance, et d'honneur, jamais il ne triomphera.[new] [bold]Edge[normal]: Prêche toujours, mon frère! -J'en fais mon devoir personnel, d'être -un monument de vertu![end] +J'en fais mon devoir personnel, d'être un +monument de vertu![end] [bold]Rydia[normal]: Monument de vertu! Mais de quoi tu parles!?[new] @@ -589,14 +579,13 @@ Je t'ai causé...tant de souffrances... Qui plus est...[new] J'ai été arrogant... impitoyable,...rancunier... -Maintenant, je suis devant toi un -homme... brisé... vaincu...et repentant.[new] +Maintenant, je suis devant toi un homme... +brisé... vaincu...et repentant.[new] Peut-être... pourrai-je soulager dans le sommeil le tourment de mon âme...[end] [bold]FuSoYa[normal]: Il nous faut à présent partir... -Je prie pour la paix sur la Planète -Bleue.[end] +Je prie pour la paix sur la Planète Bleue.[end] [bold]Rosa[normal]: Cecil...[new] [bold]Caïn[normal]: Cecil, pardonne-lui @@ -612,49 +601,45 @@ Adieu... ...mon frère![end] [bold]Ancien[normal]: Bien! Le sujet de la leçon d'aujourd'hui est la -Transfiguration et la Téléportation. [delay][0x18] -As-tu exercé ton sort[new] +Transfiguration et la Téléportation. [delay][0x18] As-tu +exercé ton sort[new] «Issue»[new] ? [bold]Porom[normal]: Oui, monsieur.[delay][0x18][new] -[bold]Ancien[normal]: Et ton sort Zone X, -Palom...? +[bold]Ancien[normal]: Et ton sort Zone X, Palom...? Palom?[new] [bold]Porom[normal]: Pas encore!![delay][0x18][close_window][end] [bold]Palom[normal]: Et alors, j'ai tué d'une seule main les hordes déferlantes de morts- vivants du mont de l'Épreuve.[new] -Comme tu peux l'imaginer,[delay][0x18] j'étais -fatigué, mais pas de repos pour les -braves![new] +Comme tu peux l'imaginer,[delay][0x18] j'étais fatigué, +mais pas de repos pour les braves! Cecil avait besoin que je lance mon puissant sort[new] «Gel»[new] -... [delay][0x18] Il a dit que j'étais bien plus -héroïque que lui...[new] -Ah, je peux lire au fond de tes yeux -que tu le penses aussi... [delay][0x18] Qu'est-ce que -tu dirais de trouver un coin plus -tranquille où je pourrais te montrer -quelque chose, hem... de tout aussi... -impressionnant...?[delay][0x10][close_window][end] +... [delay][0x18] Il a dit que j'étais bien plus héroïque +que lui...[new] +Ah, je peux lire au fond de tes yeux que +tu le penses aussi... [delay][0x18] Qu'est-ce que tu +dirais de trouver un coin plus tranquille où +je pourrais te montrer quelque chose, +hem... de tout aussi... impressionnant...?[delay][0x10][close_window][end] [bold]Palom[normal]: Ouyouyouille![new] [bold]Porom[normal]: Espèce de petit pervers![new] -[bold]Palom[normal]: J'allais juste lui[delay][0x18] montrer -mon... heu... +[bold]Palom[normal]: J'allais juste lui[delay][0x18] montrer mon... +heu... Bâton de Feu![new] [bold]Porom[normal]: Ouais, je parie... -Notre ancien est vraiment furieux -après toi! +Notre ancien est vraiment furieux après +toi! Allez![delay][0x10][close_window][end] -[bold]Ancien[normal]: Combien de fois devrai-je te -dire de ne pas sécher les leçons? [delay][0x18] -Qu'est-ce qu'il faut que je fasse pour -venir à bout d'un précoce monsieur -je-sais-tout?[new] +[bold]Ancien[normal]: Combien de fois devrai-je te dire +de ne pas sécher les leçons? [delay][0x18] Qu'est-ce +qu'il faut que je fasse pour venir à bout +d'un précoce monsieur je-sais-tout?[new] Peut-être que de recopier des sorts va t'aider à voir l'importance des leçons! [delay][0x18][close_window][end] @@ -663,17 +648,17 @@ t'aider à voir l'importance des leçons! [delay][0x18][close_window][end][bold]Porom[normal]: Tu l'as bien cherché![delay][0x10][close_window][end] -[bold]Chambellan[normal]: ...En, outre, vous -manquez de discipline pour être un -dirigeant efficace... [delay][0x18][close_window][end] +[bold]Chambellan[normal]: ...En, outre, vous manquez +de discipline pour être un dirigeant +efficace... [delay][0x18][close_window][end] [bold]Edge[normal]: Assez! Je te demande quelques suggestions pour que je m'améliore... [delay][0x18] et tu me sors une un roman gigantesque! [delay][0x10][close_window][end] -[bold]Chambellan[normal]: Je n'ai même pas -encore commencé. +[bold]Chambellan[normal]: Je n'ai même pas encore +commencé. Ensuite, vos compagnes laissent quelque peu à désirer... [delay][0x18][new] [bold]Edge[normal]: Qu'est-ce qu'elles ont qui ne @@ -682,9 +667,9 @@ Il se trouve que j'aime les femmes... [delay][0x18][new] [bold]Chambellan[normal]: Ce n'est pas ce que je voulais dire. vous vous cognez[new] «accidentellement»[new] -dans chaque jolie fille que vous voyez, -et vous êtes pris[delay][0x18] de convulsions quand il -y en a une qui se penche pour ramasser +dans chaque jolie fille que vous voyez, et +vous êtes pris[delay][0x18] de convulsions quand il y +en a une qui se penche pour ramasser quelque chose. [bold]Edge[normal]: Bon, bon! Je vais me ranger! [delay][0x18][new] @@ -693,20 +678,20 @@ pour changer! [delay][0x18][close_window][end] [bold]Edge[normal]: Mais Rydia... Beauté, intelligence, et une langue -acérée... [delay][0x18] Maintenant, il y a une femme -qui peut me faire me ranger![new] +acérée... [delay][0x18] Maintenant, il y a une femme qui +peut me faire me ranger![new] Bon sang, ce que j'ai besoin d'elle... [delay][0x18][close_window][end] [bold]Léviathan[normal]: C'est une fille incroyable![new] -[bold]Asura[normal]: Je n'aurais jamais cru qu'elle -irait si loin... [delay][0x18][close_window][end] +[bold]Asura[normal]: Je n'aurais jamais cru qu'elle irait +si loin... [delay][0x18][close_window][end] [bold]Rydia[normal]: N'est-ce pas vrai... Cecil![delay][0x10][close_window][end] [bold]Enfant Monstre[normal]: Hé, Rydia. -Comment ça se fait que j'aie des crocs -et pas toi? +Comment ça se fait que j'aie des crocs et +pas toi? J'aimerais être comme toi.[delay][0x8][close_window][end] [bold]Rydia[normal]: De quoi parles-tu? @@ -716,11 +701,11 @@ aux autres.[new] Alors, tu vois, nous ne sommes pas si différents. [delay][0x18][close_window][end] -[bold]Asura[normal]: Notre monde va être -intéressant dorénavant, tu ne crois pas?[new] -[bold]Léviathan[normal]: Oui![delay][0x10] Elle a même rendu -une ancienne entité comme moi excitée -par l'avenir! +[bold]Asura[normal]: Notre monde va être intéressant +dorénavant, tu ne crois pas?[new] +[bold]Léviathan[normal]: Oui![delay][0x10] Elle a même rendu une +ancienne entité comme moi excitée par +l'avenir! Quelle adorable jeune femme! [delay][0x10][close_window][end] [bold]Rydia[normal]: La beauté intérieure est la @@ -728,7 +713,8 @@ plus importante, pourtant...[delay][0x10][close_window][end] Prince![delay][0x8][close_window][end] -«Chante-nous une autre chanson sur le paladin!»[new] +«Chante-nous une autre chanson sur le +paladin!»[new] [delay][0xc] [bold]Edward[normal]: Pas tant que vous n'avez pas fini le travail d'aujourd'hui. @@ -741,15 +727,15 @@ pour nous.[new] Il nous a débarrassés de ces monstres effrayants. [delay][0x11] Mais il y a des choses pires que les monstres.[new] -Nous ne voulons pas que nos mamans -et papas tombent malades et meurent. [delay][0x11] -Voilà pourquoi nous devons reconstruire -notre château.[new] -Et nous avons besoin de l'aide de tout -le monde aide, même vous, petits -enfants. [delay][0x11] Dites-vous... qu'après avoir fini -votre travail, je vais vous chanter une -chanson super-spéciale! [delay][0x10][close_window][end] +Nous ne voulons pas que nos mamans et +papas tombent malades et meurent. [delay][0x11] Voilà +pourquoi nous devons reconstruire notre +château.[new] +Et nous avons besoin de l'aide de tout le +monde aide, même vous, petits enfants. [delay][0x11] +Dites-vous... qu'après avoir fini votre +travail, je vais vous chanter une chanson +super-spéciale! [delay][0x10][close_window][end] «D'accord! Souviens-toi, tu as promis!»[new] [delay][0x8][close_window][end] @@ -766,8 +752,8 @@ que toi et ton père souriiez sur nous...[delay][0x18][close_window][end] +Je suis certain que tu vas rendre à Fabul +sa gloire passée! [delay][0xd][close_window][end] Lali-Ho![delay][0x10][close_window][end] [bold]Giotto[normal]: Bien! -Mettons-nous au travail et restaurons -ce château! [delay][0x18][close_window][end] +Mettons-nous au travail et restaurons ce +château! [delay][0x18][close_window][end] -«Majesté! Nous n'avons pas assez de matières premières pour ça, Lali!»[new] +«Majesté! Nous n'avons pas assez de +matières premières pour ça, Lali!»[new] [delay][0x18][close_window][end] [bold]Giotto[normal]: Les chars! @@ -857,8 +844,8 @@ Probablement...[delay][0x20][close_window][end] [bold]Cid[normal]: Qu'est-ce qui... Vous êtes ENCORE là, tous les deux!? [delay][0x18] -C'est une belle journée, et tout le -monde arrive![new] +C'est une belle journée, et tout le monde +arrive![new] Alors dépêchez-vous![new] [bold]Rosa[normal]: J'en suis désolée.[delay][0x10][close_window][end] @@ -884,14 +871,13 @@ Prends...Prends ceci! Utilise...le![end] [bold]Rosa[normal]: Ça faisait tellement longtemps -que nous n'avions pas vu tout le monde. -[delay][0x18] Ils devraient arriver à partir de +que nous n'avions pas vu tout le monde. [delay][0x18] +Ils devraient arriver à partir de maintenant![new] Cecil, dépêche-toi, toi aussi![new] [bold]Cecil[normal]: J'arrive, Rosa.[delay][0x18][close_window][end] -[bold]Cecil[normal]: Je l'ai entendue... j'en suis -sûr... +[bold]Cecil[normal]: Je l'ai entendue... j'en suis sûr... La voix de mon frère... [delay][0x20] Il a dit... Au revoir... [delay][0x10][close_window][end] @@ -925,18 +911,17 @@ Ils vont...[end] [bold]Ancien[normal]: Écoutez, tout le monde![end] -[bold]Ancien[normal]: Il est temps pour nous de -prier pour eux... ...non, nous devons prier -pour la Terre![end] +[bold]Ancien[normal]: Il est temps pour nous de prier +pour eux... ...non, nous devons prier pour +la Terre![end] [bold]Ancien[normal]: Palom, Porom! -Nous devons envoyer les prières de -tout le monde à Cecil![end] +Nous devons envoyer les prières de tout +le monde à Cecil![end] [bold]Yang[normal]: M. Cecil...![end] -[bold]Edward[normal]: Montrez-nous le vrai -courage![end] +[bold]Edward[normal]: Montrez-nous le vrai courage![end] [bold]Cid[normal]: On t'attend tous!![end] @@ -959,13 +944,11 @@ Reçois nos prières..!![end] Ces deux-là sont les magiciens jumeaux, Palom et Porom.[new] Ils sont jeunes et encore en formation, -mais ils possèdent un talent très -précoce...[new] +mais ils possèdent un talent très précoce...[new] [bold]Palom[normal]: Attention les yeux! Je vais t'aider, alors sois reconnaissant![new] [bold]Ancien[normal]: Palom! -Qu'est-ce que je t'ai dit sur -l'arrogance?[end] +Qu'est-ce que je t'ai dit sur l'arrogance?[end] [bold]Caïn[normal]: Cecil...[end] @@ -989,8 +972,8 @@ Chimères... et reviens ici...[new] [bold]Roi Baron[normal]: Le regard dans tes yeux est un regard de tristesse, Cecil...[new] Oui, c'est vraiment moi, j'ai... j'ai été -assassiné, mais je suis devenu l'âme -d'une Chimère...[new] +assassiné, mais je suis devenu l'âme d'une +Chimère...[new] L'Invocatrice de Mist pourrait appeler mon nom, mais vous devez être testés...[end] @@ -1032,8 +1015,8 @@ Palom![end] [bold]Porom[normal]: Veuillez pardonner son insolence.[new] -[bold]Palom[normal]: Je vois pourquoi vous êtes -les amis de Cecil. +[bold]Palom[normal]: Je vois pourquoi vous êtes les +amis de Cecil. Vous étiez tous les deux les pantins de Baron.[end] diff --git a/text/fr/bank2.xml b/text/fr/bank2.xml index fbdcec0..3b846b5 100644 --- a/text/fr/bank2.xml +++ b/text/fr/bank2.xml @@ -5,8 +5,8 @@ Le village de Mist se trouve de l'autre côté de la grotte au nord-ouest![end] Le roi se comporte de plus en plus bizarrement! -Et tous ceux qui s'opposent à lui -finissent comme Cid...[end] +Et tous ceux qui s'opposent à lui finissent +comme Cid...[end] Seigneur Cecil! Vengez le roi![end] Pourquoi le roi enseignait-t-il la lame @@ -16,15 +16,15 @@ Il n'était jamais comme ça, avant. Pourquoi a-t-il changé?[end] C'était vous, ce chevalier noir! Ce que vous êtes splendide, maintenant![end] -J'ai un mauvais pressentiment à propos -de Mist...[end] -Un moine étranger a été placé à la -tête des gardes. +J'ai un mauvais pressentiment à propos de +Mist...[end] +Un moine étranger a été placé à la tête +des gardes. J'ai entendu dire qu'il recherchait quelqu'un.[new] Il doit être à l'auberge...[end] -J'ai entendu dire que le roi a été tué -et remplacé par un monstre. +J'ai entendu dire que le roi a été tué et +remplacé par un monstre. Et il n'a pas non plus d'héritier...[end] Ouah, c'est un chevalier noir! Effrayant! @@ -34,25 +34,23 @@ vraiment mort... Je l'aimais plutôt![end] Seigneur Cecil! Tuez Golbez!![end] -La porte du bâtiment à l'ouest de la -ville? +La porte du bâtiment à l'ouest de la ville? Elle donne sur une voie navigable -souterraine qui mène au château.[new] +souterraine qui mène au château. Mais maintenant elle est scellée.[end] -C'est la première fois depuis la -fondation de Baron qu'on n'a pas de roi...[end] +C'est la première fois depuis la fondation +de Baron qu'on n'a pas de roi...[end] Le chevalier noir! Non...m-m-monsieur, je n'ai rien dit contre le roi! Je...je danserai pour vous.[new] Ça vous va?[end] -Le roi a été vraiment dur, -dernièrement,... +Le roi a été vraiment dur, dernièrement,... Et je n'ai pas le droit de danser. Déçu?[end] C'était vous, ce chevalier noir! -Vous êtes bien mieux sans cette -armure lugubre et toute pleine de sueur! +Vous êtes bien mieux sans cette armure +lugubre et toute pleine de sueur! Allez, dansons![end] Non seulement ce feu mystérieux a tué @@ -65,8 +63,8 @@ sous le château de Baron... On dit que son épée tue ses ennemis d'un seul coup![end] Nous, les invocateurs, avons la capacité -de faire venir des montres du monde -des Chimères...[new] +de faire venir des montres du monde des +Chimères...[new] Un endroit qui se trouverait loin sous la surface de la Terre.[end] @@ -81,19 +79,19 @@ Qui est Anna? C'est une fille qui vivait ici, elle est tombée amoureuse d'un barde errant.[new] Son père, maître Tellah, n'acceptait -pas qu'ils se fréquentent, alors ils se -sont enfuis de Kaïpo.[end] -Je veux être danseuse à Damcyan, mais -il y a beaucoup de monstres qui rôdent +pas qu'ils se fréquentent, alors ils se sont +enfuis de Kaïpo.[end] +Je veux être danseuse à Damcyan, mais il +y a beaucoup de monstres qui rôdent dans le canal souterrain. Tu veux voir ma danse synchronisée?[end] -Le canal souterrain est au nord-est, -mais j'ai entendu dire que huit féroces -serpents de mer en gardent la sortie![end] +Le canal souterrain est au nord-est, mais +j'ai entendu dire que huit féroces serpents +de mer en gardent la sortie![end] Le château qui est au nord, Damcyan, gouverne ce désert. -J'ai entendu dire que le prince a une -voix angélique.[end] +J'ai entendu dire que le prince a une voix +angélique.[end] Si tu emmènes une petite fille avec toi, tu devrais la mettre à l'arrière.[end] @@ -104,15 +102,14 @@ Crapo![end] Toi, devenir paladin? Et puis quoi, encore?[end] T[end] -De tous ceux qui ont essayé, c'est toi -qui es devenu paladin...[end] +De tous ceux qui ont essayé, c'est toi qui +es devenu paladin...[end] Sais-tu combien nous avons souffert à cause de toi?[end] Oh, bonjour Palom et Porom. -La Montagne de l'Épreuve se situe à -l'est.[end] -J'ai senti que tu peinais sous le poids -de tes péchés... +La Montagne de l'Épreuve se situe à l'est.[end] +J'ai senti que tu peinais sous le poids de +tes péchés... Je prierai pour toi aussi.[end] Je n'ai rien à te dire! Fiche-moi la paix![end] @@ -122,16 +119,15 @@ Ta lame noire ne sert à rien![end] Toi... un paladin!?[end] Pourquoi les hommes font-ils du mal à d'autres hommes?[end] -Endure le jugement et accepte la -lumière sacrée![end] +Endure le jugement et accepte la lumière +sacrée![end] N'oublie pas l'esprit du paladin.[end] Sale fumier! T'en as du cran de venir ici![end] -Nombreux sont ceux qui se sont -mesurés à la Montagne de l'Épreuve, -mais aucun n'en est jamais revenu.[end] -Ça ne veut pas dire que je t'ai -pardonné![end] +Nombreux sont ceux qui se sont mesurés +à la Montagne de l'Épreuve, mais aucun +n'en est jamais revenu.[end] +Ça ne veut pas dire que je t'ai pardonné![end] Oh! C'est le... chevalier noir de Baron!![end] Oh! @@ -143,18 +139,17 @@ Pour une surprise..![end] T[end] C'est la Route du Démon qui mène vers Baron. -Pour nous protéger de futures -invasions, nous l'avons scellée.[end] -La Route du Démon est une -mystérieuse route dimensionnelle. +Pour nous protéger de futures invasions, +nous l'avons scellée.[end] +La Route du Démon est une mystérieuse +route dimensionnelle. Emprunter cette route draine beaucoup d'énergie vitale, d'où son nom.[end] Ou...Ouah, Vous êtes immenses! Vous êtes des géants?[end] Vous êtes des humains, pas vrai? -Faites gaffe de ne marcher sur -personne![end] +Faites gaffe de ne marcher sur personne![end] Il doit vous falloir énormément de nourriture pour remplir vos énormes estomacs! @@ -183,8 +178,8 @@ Merci à vous![end] Ohé, salut! Vous voulez nager avec moi?[end] -Bienvenue à Troia, la cité de l'eau et -des forêts![end] +Bienvenue à Troia, la cité de l'eau et des +forêts![end] Pourquoi nagez-vous en armure? Elle va rouiller! Enlevez-la, idiots![end] @@ -201,16 +196,16 @@ envoyer ta voix très loin![end] .... Laissez-moi tranquille. Je prends un bain de soleil![end] -On extrait des joyaux dans la grotte -au nord. +On extrait des joyaux dans la grotte au +nord. Par contre, on ne peut pas porter de métal du tout.[new] Il devient vraiment très lourd...[end] C'est la ville des gens de sang nain... Agalt.[end] -Selon une de nos légendes, tout -consiste en un avant et un arrière. +Selon une de nos légendes, tout consiste +en un avant et un arrière. Non, ce monde ne fait pas exception...[end] Comme je descends des Nains, je suis vraiment petit! @@ -255,8 +250,8 @@ Buvez donc un coup. Hein?... Oh, non, monsieur.[new] Votre argent n'est pas bon, ici.[end] -On dit que Cid a été enfermé -dans le château! +On dit que Cid a été enfermé dans +le château! Et il a aussi caché le nouveau modèle d'aéronef![end] M. Cecil, voulez-vous un verre? @@ -264,8 +259,8 @@ Comme vous êtes splendide, maintenant! Asseyez-vous, c'est pour la maison![end] C'est... c'est Cecil des Ailes Rouges! Je n'ai rien fait de mal! -Je paie toujours la totalité de mes -impôts à temps![end] +Je paie toujours la totalité de mes impôts +à temps![end] Les soldats du château font ce que bon leur semble au bar![end] La ville a enfin retrouvé son esprit @@ -275,12 +270,10 @@ C'était toi, ce chevalier noir, là, hein? Je te trouve bien mieux comme ça.[end] T[end] Vous êtes costauds! -Vous avez vraiment rossé de ces -soldats! -Vous me plaisez![new] +Vous avez vraiment rossé de ces soldats! +Vous me plaisez! Cette nuit, restez ici gratuitement![end] -Hé, les boissons sont toujours pas -prêtes? +Hé, les boissons sont toujours pas prêtes? Mais vous êtes qui, vous!?[end] T[end] @@ -292,8 +285,8 @@ rrron...rrron...[end] blanche! Il se croit encore jeune....[new] Et en plus, tout le monde en ville peste -contre les soldats et le roi, mais il y a -plein de gens bien, comme vous...[new] +contre les soldats et le roi, mais il y a plein +de gens bien, comme vous...[new] Papa se chamaille sans cesse avec les habitants de la ville à ce sujet...[end] [bold]Cid[normal]: Principes de la Flottaison[end] @@ -301,8 +294,8 @@ Histoire de la Construction Navale[end] Un Guide sur les Oiseaux du Monde[end] Seigneur Cecil!? Vous êtes en vie! -Papa n'est pas revenu du château -depuis longtemps.[new] +Papa n'est pas revenu du château depuis +longtemps.[new] Il paraît qu'il aurait été emprisonné! Oh, mon Dieu, je suis si inquiète... S'il vous plaît, trouvez-le[end] @@ -316,8 +309,8 @@ Et évitez qu'il s'attire des ennuis! Est-ce qu'il retravaille sur l'aéronef?[end] [bold]Cid[normal]: Zzz...Zzz....[end] -[bold]Mère de Rosa[normal]: Qu'est-ce que le -roi mijote, ces temps-ci... +[bold]Mère de Rosa[normal]: Qu'est-ce que le roi +mijote, ces temps-ci... Il paraît que vous avez fait des choses horribles à l'étranger![new] Surtout, n'embarque pas Rosa dans @@ -335,10 +328,10 @@ Je n'aurais jamais dû te laisser devenir mage blanc.[new] [bold]Rosa[normal]: Non, Maman! J'ai bien fait! -Cecil est un guerrier, alors je -peux l'assister![new] -Et tu as combattu aux côtés de papa -en tant que mage blanc, autrefois![new] +Cecil est un guerrier, alors je peux +l'assister![new] +Et tu as combattu aux côtés de papa en +tant que mage blanc, autrefois![new] [bold]Mère de Rosa[normal]: ... Rosa... Ton père... c'était un grand chevalier... je @@ -357,10 +350,10 @@ Anna s'est sauvée de chez elle... Je me demande bien pourquoi...[end] Salut, je suis un savant itinérant.[new] -Je veux faire des recherches à Fabul, -une ville à l'est de Damcyan, mais au -canal souterrain, il y a un drôle de vieux -qui ne veut pas me laisser passer...[end] +Je veux faire des recherches à Fabul, une +ville à l'est de Damcyan, mais au canal +souterrain, il y a un drôle de vieux qui ne +veut pas me laisser passer...[end] Oh, comme c'est singulier... Un client...[new] À cause de tous les monstres, nous @@ -369,18 +362,17 @@ nos jours.[end] Apaise ta cuisante soif du désert avec une micro infusion spéciale de Kaïpo! Carte d'identité valide obligatoire.[end] -Seule la famille royale peut pénétrer -dans la grotte du Fourmilion qui est à -l'est de Damcyan.[new] -Si les gens ordinaires y étaient -autorisés, ça remonterait vraiment les -affaires. +Seule la famille royale peut pénétrer dans +la grotte du Fourmilion qui est à l'est de +Damcyan.[new] +Si les gens ordinaires y étaient autorisés, +ça remonterait vraiment les affaires. Tu te rends compte...tous ces joyaux..![end] -Une fille de Baron s'est effondrée juste -à l'entrée du village. -Sa fièvre la faisait délirer et appelait -sans arrêt[new] +Une fille de Baron s'est effondrée juste à +l'entrée du village. +Sa fièvre la faisait délirer et appelait sans +arrêt «Cecil, Cecil...»[new] .[end] Ainsi, tu es le Cecil qu'elle appelait. @@ -389,7 +381,8 @@ Afin de guérir la fièvre du désert, il te faut la Lumière du Désert... un joyau rarissime qu'on trouve uniquement dans l'antre du Fourmilion...[end] -«La Lumière du Désert est le seul remède contre la fièvre du désert...»[end] +«La Lumière du Désert est le seul remède +contre la fièvre du désert...»[end] [bold]Rosa[normal]: ... [music][0x13] Ooh... Cecil... Ne m'abandonne pas, Cecil![end] @@ -401,12 +394,12 @@ Reviens nous voir bientôt![end] Que veux-tu nous voler, cette fois![end] La Montagne de l'Épreuve? -Rien que[new] +Rien que «aller là-bas»[new] , ça ne veut rien dire![end] Ne pardonnez jamais le pillage baronien -qui nous a volé notre cristal et la vie -des nôtres![end] +qui nous a volé notre cristal et la vie des +nôtres![end] Je ne peux pas te croire... Tu es devenu...[end] Nos amis! @@ -415,8 +408,8 @@ Palom, Porom! N'ayez pas confiance en cet homme![end] Superbe... Alors c'est ça, un paladin...[end] -La f-f-ferme -hic- J'ai pas peur -d'aucun ch-chevalier noir![end] +La f-f-ferme -hic- J'ai pas peur d'aucun +ch-chevalier noir![end] -hic- Toi, devenir un paladin! Hi hi hi! Ha ha ha ha ha![end] @@ -440,8 +433,8 @@ Vous allez gravir la montagne de l'Épreuve![end] Wow, tu es vraiment splendide![end] [bold]Cecil[normal]: Argl![end] -[bold]Cecil[normal]: J'ai mis un petit peu de -poison dans ton verre! +[bold]Cecil[normal]: J'ai mis un petit peu de poison +dans ton verre! Zut! Pas assez fort![end] @@ -451,18 +444,18 @@ Pas assez fort![end] T[end] T[end] -Feu, terre, eau, et vent sont la base -de toute chose.[end] +Feu, terre, eau, et vent sont la base de +toute chose.[end] Méthodes de respiration pour faire de la magie noire.[end] -Mon premier[new] +Mon premier «Soin»[end] T[end] T[end] L'ancien pardonne tout. Mais je ne te pardonnerai pas...[end] -Si tu deviens un paladin, j'aurai -confiance en toi.[end] +Si tu deviens un paladin, j'aurai confiance +en toi.[end] Nous avons confiance en toi![end] C'est la Maison des Prières. L'ancien va écouter ton histoire.[end] @@ -475,14 +468,14 @@ Tout commence à partir d'un innocent bébé...[end] Le paladin est un chevalier sacré, l'opposé d'un chevalier noir.[end] -Tu es un paladin! ...Peut-être que c'était -le destin.[end] +Tu es un paladin! ...Peut-être que c'était le +destin.[end] [bold]Fille[normal]: Qu'est-ce qui ne va pas?[new] [bold]Ancien[normal]: Où est Palom?[new] [bold]Fille[normal]: Pfff... Palom, ça ne va pas recommencer![end] -[bold]Garçon[normal]: Alors c'est toi le mec de -Baron, hein? +[bold]Garçon[normal]: Alors c'est toi le mec de Baron, +hein? Le vieux m'a dit de t'aider, il faut croire que je n'ai pas le choix.[new] Sois-m'en reconnaissant![end] @@ -492,23 +485,22 @@ Je suis enchantée de faire votre connaissance.[end] [bold]Porom[normal]: Hé, Palom, allez salue-le aussi![end] -[bold]Palom[normal]: Content de te rencontrer, -mon pote![end] +[bold]Palom[normal]: Content de te rencontrer, mon +pote![end] [bold]Palom[normal]: Le mage noir Palom et le -mage blanc Porom se sont joints à -toi! [music][0x29][delay][0x28][end] -[bold]Ancien[normal]: Maintenant, va sur la -Montagne de l'Épreuve! +mage blanc Porom se sont joints à toi! +[music][0x29][delay][0x28][end] +[bold]Ancien[normal]: Maintenant, va sur la Montagne +de l'Épreuve! Palom! Porom![new] Je compte sur vous![end] Tu es maître de ton destin. -Tout ce que je peux faire à présent, -c'est prier pour toi...[new] +Tout ce que je peux faire à présent, c'est +prier pour toi...[new] Palom, Porom, tenez-vous bien, -et essayez de ne pas gêner M. -Cecil.[end] +et essayez de ne pas gêner M. Cecil.[end] Palom et Porom...! Je vois... mais est-ce que le destin prévoyait pour eux de se sacrifier...[end] @@ -539,15 +531,13 @@ si tu vois ce que je veux dire.[end] Bien! Aujourd'hui, J'ai eu un rencard au comptoir![new] -Demain, c'est au-dessus que ça se -passe![end] +Demain, c'est au-dessus que ça se passe![end] Salut, chéri! -clin d'il[end] -Je suis content d'avoir vécu si -longtemps! +Je suis content d'avoir vécu si longtemps! Je préfère cet endroit au Paradis![end] Tu as l'air de vouloir passer un bon -moment avec une femme plus âgée, et -plus mature... +moment avec une femme plus âgée, et plus +mature... Non mais c'est quoi ce regard!?[end] Oh, ma poupée! Je crois que je craque pour toi! @@ -555,8 +545,8 @@ Aaah! T'es un mec!![end] T[end] Quelle que soit la façon dont tu les -regardes, et je le fais souvent, les filles -ici sont terribles![end] +regardes, et je le fais souvent, les filles ici +sont terribles![end] Bonjour! Quel est ton désir?[end] Menteur! @@ -590,16 +580,15 @@ Bienvenue. Ça va bientôt être l'heure du spectacle. Si tu apprécies, pense à être généreux avec le pourboire.[end] -Ha dis donc, qu'est-ce que j'aimerais -être aussi jeune que toi...[end] +Ha dis donc, qu'est-ce que j'aimerais être +aussi jeune que toi...[end] T[end] -Grâce à l'eau pure et au sol fertile, -nous pouvons avoir de nombreux -légumes frais.[new] -C'est donc un cadre idéal pour élever -des chocobos.[end] +Grâce à l'eau pure et au sol fertile, nous +pouvons avoir de nombreux légumes frais. +C'est donc un cadre idéal pour élever des +chocobos.[end] T[end] Biologie des Chocobos[end] Vous aussi pouvez faire éclore des @@ -634,17 +623,15 @@ T[end] T[end] T[end] Je veux voler sur un chocobo noir, mais -ils ont toujours peur quand je -m'approche. +ils ont toujours peur quand je m'approche. Est-ce que je ne les aime pas assez?[end] C'est l'observatoire de Colliro. -Le seul télescope au monde se trouve -ici.[new] +Le seul télescope au monde se trouve ici. Il y a peu, phénomènes étranges ont eu -lieu sur la lune. -Nous avons fait tout notre possible -pour les observer.[new] +lieu sur la lune.[new] +Nous avons fait tout notre possible pour +les observer. Qu'est-ce qui se passe, là- bas..?[end] Mon mari est tellement absorbé par ses observations qu'il en oublie de boire et @@ -665,21 +652,19 @@ même couleur que notre sang...[new] J'espère que rien de mauvais ne se prépare...[end] -J'ai vu des vaisseaux rouges aller dans -le cratère au nord![end] +J'ai vu des vaisseaux rouges aller dans le +cratère au nord![end] Même quand le reste du monde souffre -des ravages de la guerre, c'est paisible, -ici.[new] +des ravages de la guerre, c'est paisible, ici. Par contre, nous sommes bien atteints par les tremblements de terre.[end] -Ma grand-mère est la doyenne du -village. +Ma grand-mère est la doyenne du village. Elle sait tout![end] -Nos ancêtres sont venus du grand -trou, dans les montagnes au nord.[new] -Mais maintenant le trou est bouché et -on ne peut y aller, ni par la terre, ni -par les airs.[end] +Nos ancêtres sont venus du grand trou, +dans les montagnes au nord.[new] +Mais maintenant le trou est bouché et on +ne peut y aller, ni par la terre, ni par les +airs.[end] Il y a une ancienne légende... Quand nous retournons la Pierre de Magma à son lieu de naissance, le chemin @@ -712,18 +697,18 @@ Golbez?[end] Vous partez tôt demain matin, n'est-ce pas? Reposez-vous bien cette nuit.[end] -Jusqu'à ce que vous ayez accompli -votre mission, nous avons l'ordre de ne -pas vous laisser entrer dans le château![end] +Jusqu'à ce que vous ayez accompli votre +mission, nous avons l'ordre de ne pas +vous laisser entrer dans le château![end] Qui diable es-tu? Tu as un passe pour entrer?[end] Il se fait tard... Tu ne devrais pas partir maintenant.[end] -J'ai entendu dire qu'il y a des moments -où les Chimères sont immunisées aux +J'ai entendu dire qu'il y a des moments où +les Chimères sont immunisées aux attaques.[end] -J'ai l'impression de t'avoir déjà vu -quelque part...[end] +J'ai l'impression de t'avoir déjà vu quelque +part...[end] L'accès à cette tour est interdit.[end] [bold]Cid[normal]: Te revoilà, Cecil![end] [bold]Cid[normal]: Rosa était inquiète! @@ -747,25 +732,23 @@ Et puis maintenant, il te dit d'aller chasser les Chimères? Les villageois sont pertutbés... Et je parle même pas de moi...[new] -Enfin, de toute façon, sois prudent, -reçu? +Enfin, de toute façon, sois prudent, reçu? Je rentre à la maison.[new] -J'ai pas mal bossé ces derniers temps... -et ma fille me pique des crises à cause -de ça![end] -As-tu vu notre patron Cid dans -le coin?[new] +J'ai pas mal bossé ces derniers temps... et +ma fille me pique des crises à cause de ça![end] +As-tu vu notre patron Cid dans le +coin?[new] Il s'est mis à penser à Dieu Sait Quoi, nous laissant seuls à nettoyer les aéronefs.[end] Patron! Et M. Cecil![end] -On dirait que le patron fait comme à -son habitude, non?[end] +On dirait que le patron fait comme à son +habitude, non?[end] Quoi, on doit ENCORE passer une nuit blanche sur ce projet? -Si ce n'était pas un soudard pareil, on -y prendrait du plaisir.[new] +Si ce n'était pas un soudard pareil, on y +prendrait du plaisir.[new] Ah! N...ne le dis pas au patron! D...dis-lui que... heu... le travail, c'est @@ -780,8 +763,8 @@ Ouaip...Je suis devenu aussi bon que le patron à ça... N...Ne va pas lui répéter ça![end] -Est-ce...est-ce que le Prince Edward -va bien...[end] +Est-ce...est-ce que le Prince Edward va +bien...[end] M. Yang! Vous êtes de retour. @@ -795,24 +778,21 @@ manière ou d'une autre.[end] Ah, M. Cecil![end] J'adore être une grenouille. -Plein de baisers de jeunes filles -blondes...[end] +Plein de baisers de jeunes filles blondes...[end] Bienvenue au château de Troia![end] -Oui, je m'appelle Kermit, comment tu -sais?[end] +Oui, je m'appelle Kermit, comment tu sais?[end] Oh, des voyageurs! Faites ici comme chez vous.[end] Croa-a! Croa-a! J'adore être vert![end] Vous êtes là pour le cristal? -Alors vous devriez parler aux clercs -dans le château.[end] +Alors vous devriez parler aux clercs dans +le château.[end] T[end] -Les Clercs sont les dignes messagères -de Dieu. -Veuillez vous comporter -convenablement.[end] +Les Clercs sont les dignes messagères de +Dieu. +Veuillez vous comporter convenablement.[end] T[end] @@ -846,14 +826,14 @@ démon..?[end] [bold]Beigan[normal]: Quoi!? Où!?[end] [bold]Palom[normal]: Rha là là! -On ne peut pas sortir et faire -confiance à tout le monde![new] +On ne peut pas sortir et faire confiance +à tout le monde![new] [bold]Cecil[normal]: Beigan aussi..? Combien de gens de Baron Golbez contrôle-t-il..?!![end] -J'ai perçu une drôle d'atmosphère -autour du roi, dernièrement...[end] +J'ai perçu une drôle d'atmosphère autour +du roi, dernièrement...[end] M. Cecil! Prenez le trône![end] Je n'aime pas ce naze de Beigan![end] @@ -865,12 +845,11 @@ Le village de Mist est au nord-ouest de Baron. On dit qu'il est toujours couvert d'une épaisse nappe de brouillard.[end] -Nous défendrons le château au nom -des chevaliers dragons![end] +Nous défendrons le château au nom des +chevaliers dragons![end] Si le capitaine des chevaliers dragons -Caïn et Cecil font équipe, -cette bague est sûre d'arriver à bon -port![end] +Caïn et Cecil font équipe, cette +bague est sûre d'arriver à bon port![end] M. Caïn est intouchable![end] On dit beaucoup de choses sur sa majesté, mais si elle entendait ça...[end] @@ -888,8 +867,8 @@ protéger...[end] [bold]Roi Baron[normal]: Cecil! Tu es sauf! -Et je vois que tu es devenu un -puissant guerrier![new] +Et je vois que tu es devenu un puissant +guerrier![new] [bold]Cecil[normal]: Majesté...[new] [bold]Roi Baron[normal]: Mais tu es devenu un paladin. @@ -899,10 +878,9 @@ Lumière Sacrée...[new] [bold]Cecil[normal]: Roi Baron?..[end] «Pourquoi tu... misérable imposteur!»[end] [bold]Cid[normal]: Fripouille! -Me mettre dans un trou puant comme -ça![new] +Me mettre dans un trou puant comme ça! Je m'en vais te botter le train, tu vas -voir! +voir![new] H..hein?[end] [bold]Cecil[normal]: Cid![new] [bold]Cid[normal]: Cecil! @@ -916,8 +894,8 @@ Elle a couru à ta recherche...[new] [bold]Cid[normal]: Quoi?! Alors que tu étais là pour la protéger? Mais ce Golbez....[new] -Non seulement il abuse de mes -aéronefs, mais de Rosa aussi!?[end] +Non seulement il abuse de mes aéronefs, +mais de Rosa aussi!?[end] [bold]Tellah[normal]: Cette fille est en danger. Vite, emmenez-nous à l'aéronef![end] [bold]Cid[normal]: C'est qui, cette épave?[new] @@ -942,21 +920,20 @@ votre connaissance, monsieur. C'est dangereux, ici, alors il faudrait se hâter.[new] [bold]Cid[normal]: Hé! -Tu connais vraiment les bonnes -manières![end] +Tu connais vraiment les bonnes manières![end] [bold]Cecil[normal]: Cid, où est le nouveau modèle d'aéronef?[new] [bold]Cid[normal]: Héhéhé...[end] [bold]Cid[normal]: Nous ne laisserons plus les monstres prendre le château![end] -[bold]Cid[normal]: Là où personne n'aurait -jamais pensé mettre son nez! +[bold]Cid[normal]: Là où personne n'aurait jamais +pensé mettre son nez! Je viens de le terminer![end] [bold]Tellah[normal]: Nous n'avons pas le temps pour ça! La vie de Rosa ne tient qu'à un fil![end] -[bold]Cid[normal]: Merde alors, quel grincheux -tu fais! +[bold]Cid[normal]: Merde alors, quel grincheux tu +fais! Ça va, j'ai pigé! Allez, c'est par là![end] [bold]Roi Baron[normal]: En effet! @@ -985,16 +962,14 @@ C'est interdit![end] les magiciens Mythidiens qui ont résisté. Tu peux leur parler à travers les barreaux.[end] -J'espère que nous n'aurons plus jamais -à utiliser ce donjon.[end] +J'espère que nous n'aurons plus jamais à +utiliser ce donjon.[end] Tu es ce chevalier noir! Tu crois t'en tirer comme ça!?[end] -Nous nous fichons de ce qui nous -arrive. +Nous nous fichons de ce qui nous arrive. Rendez juste le cristal à Mythidia![end] Tu ne comprends rien! -Le cristal n'est pas qu'un joyau -ordinaire![end] +Le cristal n'est pas qu'un joyau ordinaire![end] Aïe! J'ai un bleu, ici![end] @@ -1004,8 +979,8 @@ Moi? Oh, je vais beaucoup mieux![end] Capitaine...[end] Vous étiez vivant, en fin de compte![end] -Je vais me saouler pour essayer -d'oublier ce qui s'est passé à Mythidia...[end] +Je vais me saouler pour essayer d'oublier +ce qui s'est passé à Mythidia...[end] Sa majesté morte, tu es le seul qui puisse diriger Baron![end] Ce boulot m'a laissé une mauvaise @@ -1061,33 +1036,30 @@ Anna!![end] Misérable! Anna est morte à cause de vous!![new] [bold]Barde[normal]: !?[end] -[bold]Edward[normal]: La Lumière du Désert se -forme à partir des sécrétions du -Fourmilion quand il pond ses ufs.[new] +[bold]Edward[normal]: La Lumière du Désert se forme +à partir des sécrétions du Fourmilion +quand il pond ses œufs.[new] Sa grotte est à l'est, mais nous devons -traverser un plan d'eau peu profond -pour y accéder.[new] -Il y a un aéroglisseur à Damcyan qui -peut le traverser. +traverser un plan d'eau peu profond pour +y accéder.[new] +Il y a un aéroglisseur à Damcyan qui peut +le traverser. Il devrait aussi pouvoir traverser les hauts-fonds pour aller vers Kaïpo.[end] -Nous sommes les seuls -survivants. +Nous sommes les seuls survivants. Peut-être pouvons-nous nous retirer à Kaïpo...[new] Nous pouvons utiliser l'Aéroglisseur pour traverser les hauts-fonds à l'ouest pour y aller...[end] -Peut-être pouvons-nous -nous retirer à Fabul...[new] -Mais le chemin de Fabul par le mont -Hobs a été bloqué par une épaisse -couche de glace apportée par les vents -glaciaux.[end] +Peut-être pouvons-nous nous retirer à +Fabul...[new] +Mais le chemin de Fabul par le mont Hobs +a été bloqué par une épaisse couche de +glace apportée par les vents glaciaux.[end] [bold]Tellah[normal]: ....Qui est ce Golbez!?[new] -[bold]Edward[normal]: Il est venu à Baron il y a -peu et a pris le contrôle des Ailes -Rouges.[new] +[bold]Edward[normal]: Il est venu à Baron il y a peu +et a pris le contrôle des Ailes Rouges.[new] Tout ce que je peux imaginer, c'est qu'il les utilise pour rassembler les cristaux... sniff...[new] @@ -1101,7 +1073,7 @@ pas faire ça tout seul![end] aide! Je vais tuer Golbez de mes propres mains![end] -[bold]Tellah[normal]: Tellah a quitté le groupe.[end] +Tellah a quitté le groupe.[end] [bold]Edward[normal]: A... Anna... -sniff-...-snif-...[end] [bold]Rydia[normal]: Pleurnicheur![end] @@ -1128,8 +1100,7 @@ Une amie à moi s'est écroulée près de Kaïpo, frappée par la fièvre du désert.[new] Nous avons besoin de la Lumière du Désert! -De plus, nous avons besoin de votre -aide![new] +De plus, nous avons besoin de votre aide![new] [bold]Edward[normal]: Mon aide...[new] [bold]Cecil[normal]: Oui. Pour Rosa... @@ -1151,8 +1122,7 @@ Ne les laisse pas prendre ce trésor...!![end] T[end] -Nous avons perdu notre force -principale? +Nous avons perdu notre force principale? Impossible![end] Et nous restons là, inutiles...[end] Une étrange rumeur court parmi les @@ -1181,9 +1151,8 @@ l'attaque et se repose dans sa chambre.[end] T[end] -J'ai entendu dire que vous avez été -pris en embuscade au sommet du mont -Hobs! +J'ai entendu dire que vous avez été pris +en embuscade au sommet du mont Hobs! Est-ce que vous allez bien?[end] Si seulement nous avions un aéronef, nous pourrions trouver un moyen pour @@ -1192,14 +1161,12 @@ Je ne dors pas. Je médite![end] Soyez prudents![end] -Es-tu de retour de l'entraînement, -maître Yang?[end] -Wow, ça, c'était une attaque de la -mort![end] +Es-tu de retour de l'entraînement, maître +Yang?[end] +Wow, ça, c'était une attaque de la mort![end] Nous irons bien quoi qu'il arrive dans le château! -Nous avons des Moines pour le -défendre![end] +Nous avons des Moines pour le défendre![end] Je suis content que la ville de Fabul soit dans le château. Si nous avions été dehors, nous serions @@ -1212,37 +1179,37 @@ Je veux m'entraîner pour être fort et rapide comme nos Moines![end] [bold]Roi de Fabul[normal]: Misère, quel désastre... -Mais nous devons réorganiser et -fortifier nos défenses! +Mais nous devons réorganiser et fortifier +nos défenses! Ne vous inquiétez pas pour moi.[new] Pour le moment, vous devriez vous reposer.[end] [bold]Roi de Fabul[normal]: ...Oh, vraiment? Très bien, Yang! Accompagne-les et aide-les![new] -Cecil, je n'arrive pas à trouver -mes mots pour te remercier assez. +Cecil, je n'arrive pas à trouver mes +mots pour te remercier assez. Et aussi, Rosa a été capturée...[new] -Je vais ordonner qu'on affrète un -bateau immédiatement. +Je vais ordonner qu'on affrète un bateau +immédiatement. Cecil. Prends cette épée.[new] C'est l'épée d'un chevalier noir qui a est passé il y a longtemps.[new] -C'est le moins que je puisse faire pour -te remercier d'avoir défendu Fabul. ...Mais +C'est le moins que je puisse faire pour te +remercier d'avoir défendu Fabul. ...Mais c'est toujours une épée de l'obscurité...[new] Elle se montrera inutile contre le mal véritable. Vaincs Golbez![end] [bold]Roi Fabul[normal]: Si tous les cristaux sont -rassemblés, le monde entier sera dans -une crise sans précédent! +rassemblés, le monde entier sera dans une +crise sans précédent! Je compte sur toi![end] [bold]Roi Fabul[normal]: C'est la chambre de sa majesté![end] -Sa majesté était aussi un Moine, alors -ne vous inquiétez pas pour sa santé.[end] +Sa majesté était aussi un Moine, alors ne +vous inquiétez pas pour sa santé.[end] [bold]Roi Fabul[normal]: Dès que vous serez prêts, allez à l'est, vers le port. Il devrait y avoir un navire qui vous y @@ -1265,8 +1232,8 @@ de Baron![end] Voici M. Cecil. Lui et ses amis m'ont sauvé la vie.[new] [bold]Femme de Yang[normal]: Merci! -Au fait, chéri, penses-tu vraiment que -ce soit le moment de traîner par ici?[end] +Au fait, chéri, penses-tu vraiment que ce +soit le moment de traîner par ici?[end] [bold]Femme de Yang[normal]: Tu es sauf![new] [bold]Yang[normal]: Grâce à ces gens, Fabul a été sauvée.[new] @@ -1278,8 +1245,8 @@ hein?[new] [bold]Femme de Yang[normal]: Bien sûr que non! Je suis ta femme, quand même![new] Un soldat de Baron est bien venu, mais -je lui ai fichu un coup de ma poêle à -frire sur la tête![end] +je lui ai fichu un coup de ma poêle à frire +sur la tête![end] [bold]Yang[normal]: Ne reste pas là comme ça! Va battre les méchants et reviens![end] [bold]Yang[normal]: Yang est mort? @@ -1290,11 +1257,10 @@ Non...Il n'est pas...[end] [bold]Yang[normal]: Alors c'est là qu'il était... Oh, ces oignons... Ils me piquent tellement les yeux...[end] -[bold]Yang[normal]: Il ne devrait pas être dans -un état pareil! +[bold]Yang[normal]: Il ne devrait pas être dans un +état pareil! S'il te plaît...[new] -Donne-lui un bon coup de ça sur la -tête![end] +Donne-lui un bon coup de ça sur la tête![end] [bold]Yang[normal]: Obtenu la Poêle à frire de l'Amour![end] [bold]Yang[normal]: Yang?! @@ -1306,8 +1272,8 @@ remercier, mais ça pourrait bien servir.[end] [bold]Yang[normal]: Obtenu le Hachoir à Viande![end] [bold]Yang[normal]: Ne vous inquiétez pas pour moi! -Dites à Yang de se remettre vite -et de se battre pour l'avenir du monde![new] +Dites à Yang de se remettre vite et +de se battre pour l'avenir du monde![new] Et...que je l'aime.[end] T[end] @@ -1321,8 +1287,8 @@ Nous pouvons nous reposer ici dans une tente ou une cabine, et sauvegarder la partie.[new] En vue du combat de demain, -reposons-nous dans ma tente et -soignons nos blessures![end] +reposons-nous dans ma tente et soignons +nos blessures![end] Tu veux que je danse? Quel rustre! @@ -1341,8 +1307,8 @@ des femmes.[end] Je ne suis pas qu'une vieille femme! Je suis le premier ministre! Les Clercs sont dans la salle intérieure.[end] -Un survivant de Damcyan a été jeté -sur le rivage il y a peu de temps. +Un survivant de Damcyan a été jeté sur +le rivage il y a peu de temps. Il dit que c'était le prince, ou quelque chose comme ça...[end] T[end] @@ -1351,52 +1317,50 @@ Si nous entrons en guerre, que devrons nous faire pour protéger notre pays?..[end] Les clercs sont huit surs. -Des générations durant, elles ont été -les gardiennes du cristal.[end] -Le cristal de la terre a comblé Troia -avec les bénédictions de la nature. +Des générations durant, elles ont été les +gardiennes du cristal.[end] +Le cristal de la terre a comblé Troia avec +les bénédictions de la nature. Si nous perdons le cristal, cette région deviendra un terrain vague...[end] C'est bien mieux que d'être dirigées par des hommes brutaux![end] -On dirait que vous êtes dans un -mauvais pas. -Comme promis, nous allons vous prêter -le cristal de la terre.[end] +On dirait que vous êtes dans un mauvais +pas. +Comme promis, nous allons vous prêter le +cristal de la terre.[end] Le cristal de la terre a été pris? Mon Dieu![end] -L'Elfe Noir est faible contre les armes -de métal.[new] +L'Elfe Noir est faible contre les armes de +métal.[new] Pour protéger ce point faible... il a -augmenté le champ gravitationnel dans -sa grotte.[end] +augmenté le champ gravitationnel dans sa +grotte.[end] Nous te confions le cristal. Prends-en soin![end] -Dire qu'un homme maléfique est en -train de réunir les cristaux![end] -L'Elfe Noir vit dans la grotte au -nord-est.[end] +Dire qu'un homme maléfique est en train +de réunir les cristaux![end] +L'Elfe Noir vit dans la grotte au nord-est.[end] Quelle était cette voix!?[end] Le cristal a été volé? Ne restez pas comme ça, rapportez-le![end] -Si vous pouvez récupérer le cristal, -nous promettons que nous vous le -prêterons. +Si vous pouvez récupérer le cristal, nous +promettons que nous vous le prêterons. Mais d'abord, ramenez-le ici.[end] Prenez le trésor qui est à la cave.[end] -Golbez mettant les mains sur le -cristal est bien pire que ce qui va -arriver à Troia sans lui![end] -Si vous portez des armes et des -armures de métal dans la grotte qui se -trouve au nord-est, Vous ne pourrez -même pas bouger![end] +Golbez mettant les mains sur le cristal +est bien pire que ce qui va arriver à Troia +sans lui![end] +Si vous portez des armes et des armures +de métal dans la grotte qui se trouve au +nord-est, Vous ne pourrez même pas +bouger![end] Et nous venons juste de le récupérer! Je suppose qu'il n'y a pas le choix. Nous ne faisons que vous le prêter![end] Les cristaux ont été éparpillés de par le -monde pour être sûrs que de telles -choses n'arrivent jamais.[end] +monde pour être sûrs que de telles choses +n'arrivent jamais.[end] Nous ne pouvons pas vous donner le cristal de la terre... Mais si vous nous le rapportez, nous @@ -1409,12 +1373,12 @@ incroyable.[end] Le cristal de la terre? Il a été volé par l'Elfe Noir.[end] Le pouvoir du cristal varie suivant qui le -possède! +possède![new] Si une personne maléfique l'avait, cela pourrait avoir de terribles répercussions![end] Si la rumeur disant qu'il y a plus de -quatre cristaux est vraie, il y a encore -de l'espoir.[end] +quatre cristaux est vraie, il y a encore de +l'espoir.[end] Troia est gouvernée par nous, les huit Clercs. Nous étions dotées de la bénédiction du @@ -1462,8 +1426,7 @@ C'est la harpe de Edward...[end] C'était une prison souterraine, mais maintenant c'est notre salle au trésor.[end] -Tu sais très bien que c'est un -mensonge![end] +Tu sais très bien que c'est un mensonge![end] Alors prends le trésor.[end] Et tu espères entrer?[end] @@ -1512,18 +1475,18 @@ Désolé, c'était Minimum![end] Rosa voulait t'aider, alors elle a choisi de devenir mage blanc. Ne la tourmente pas![end] -Nous ne pouvons que prier pour que -les âmes des soldats morts puissent -reposer en paix.[end] +Nous ne pouvons que prier pour que les +âmes des soldats morts puissent reposer +en paix.[end] J'étudie les rudiments de la magie blanche. Je peux utiliser trois niveaux de magie blanche...[new] Soin, Soin 2, Soin 3![end] Dire qu'un monstre a remplacé le roi...[end] -Dernièrement, le roi a été aussi -vigoureux et robuste qu'autrefois, plein -de vie et d'énergie! +Dernièrement, le roi a été aussi vigoureux +et robuste qu'autrefois, plein de vie et +d'énergie! Mais il a quelque chose d'étrange...[end] Nous assisterons les soldats avec notre magie blanche![end] @@ -1535,19 +1498,17 @@ d'énergie au rang arrière de ton groupe![new] Si tu déplaces le curseur vers la gauche pendant un combat, tu peux inverser les rangs avant et arrière.[new] -Si tu appuies sur droite, tu vas rester -en garde![new] +Si tu appuies sur droite, tu vas rester en +garde![new] Aussi, si tu veux utiliser une arme en -tant qu'objet dans un combat, -sélectionne[new] +tant qu'objet dans un combat, sélectionne «Objet»[new] et déplace le curseur tout en haut pour sélectionner ton arme![new] -Utilise ça pour changer d'arme ou -refaire le plein de flèches, et la victoire -est à toi![end] -Tu dois prendre rapidement des -décisions au cours des combats! +Utilise ça pour changer d'arme ou refaire +le plein de flèches, et la victoire est à toi![end] +Tu dois prendre rapidement des décisions +au cours des combats! Ceux qui n'en sont pas sûrs devraient diminuer la vitesse de bataille![new] Ceux qui sont confiants en leurs @@ -1557,34 +1518,32 @@ Les monstres vont t'attaquer même pendant que tu sélectionnes des objets ou des magies... pour rendre la bataille encore plus palpitante![end] -Il y a des endroits dans les grottes où -tu peux sauvegarder ton jeu. +Il y a des endroits dans les grottes où tu +peux sauvegarder ton jeu. Utilise bien ces endroits![end] Si tu ne peux plus porter d'objets supplémentaires, tu peux les donner au Gros Chocobo dans la Forêt Chocobo![new] Si tu sens des chocobos, utilise des légumes de Gysahl![end] -L'homme qui est là-bas, c'est -Namingway. -Si tu veux changer de nom, tu n'as -qu'à le lui demander![end] +L'homme qui est là-bas, c'est Namingway. +Si tu veux changer de nom, tu n'as qu'à +le lui demander![end] Si tu te bats dans une bataille -désespérée, tu ne pourras que mourir![new] -Si tu crois être en difficulté, n'y -réfléchis pas à deux fois avant de te -sauver.[new] -Presse les boutons L et R en même -temps pour te sauver d'une bataille! +désespérée, tu ne pourras que mourir! +Si tu crois être en difficulté, n'y réfléchis +pas à deux fois avant de te sauver.[new] +Presse les boutons L et R en même temps +pour te sauver d'une bataille! Aussi, il y a des sorts que tu peux invoquer sur de multiples cibles.[new] Si tu appuies vers la gauche pendant le combat, tu sélectionneras tous les ennemis... appuyer vers la droite sélectionnera tous tes alliés![new] -Tu peux invoquer un sort sur ton -groupe entier de cette même manière -sur l'écran de menu![end] +Tu peux invoquer un sort sur ton groupe +entier de cette même manière sur l'écran +de menu![end] T[end] @@ -1648,8 +1607,8 @@ cette chute d'eau![music][0x29][delay][0x28][end] Le passage est bloqué par une épaisse couche de glace.[end] -[bold]Rosa[normal]: Rydia, essaie d'invoquer -le feu.[new] +[bold]Rosa[normal]: Rydia, essaie d'invoquer le +feu.[new] [bold]Rydia[normal]: ....[end] [bold]Rydia[normal]: ....Non.[new] [bold]Rosa[normal]: ?[new] @@ -1661,8 +1620,8 @@ Tu es la seule ici à avoir le pouvoir de faire fondre cette glace.[new] [bold]Rydia[normal]: ....[new] [bold]Rosa[normal]: Si nous ne franchissons pas -cette glace pour aller à Fabul, beaucoup -de gens seront en danger! +cette glace pour aller à Fabul, beaucoup de +gens seront en danger! S'il te plaît... essaye d'être courageuse![new] [bold]Edward[normal]: Courageuse....[new] [bold]Rosa[normal]: Rydia, s'il te plaît![new] @@ -1684,12 +1643,11 @@ Ce doit être un moine de Fabul![end] [bold]Rydia[normal]: Aidons-le![end] [bold]Moine[normal]: Merci... de m'être venus en aide quand j'en avais besoin. -Je suis Yang, le capitaine des -moines de Fabul.[new] +Je suis Yang, le capitaine des moines +de Fabul.[new] Mes hommes et moi nous entraînions ici, -sur le mont Hobs... et soudain, nous -avons été attaqués par des hordes de -monstres.[new] +sur le mont Hobs... et soudain, nous avons +été attaqués par des hordes de monstres.[new] Mes hommes... tués... tous...je suis le seul survivant...[new] [bold]Cecil[normal]: Nous faisons route vers Fabul.[new] @@ -1699,8 +1657,7 @@ cristaux...[end] [bold]Moine[normal]: Haa![end] [bold]Cecil[normal]: Qu'est-ce que c'est?[end] [bold]Rosa[normal]: À tous les coups, ces -monstres ont été envoyés par -Golbez...[end] +monstres ont été envoyés par Golbez...[end] [bold]Yang[normal]: Dans le but d'affaiblir les défenses de Fabul!?[new] [bold]Cecil[normal]: Si c'est le cas, ils peuvent @@ -1726,8 +1683,8 @@ Allons-y![new] [bold]Yang[normal]: Fabul est à l'est des montagnes. Dépêchons-nous![end] -[bold]Yang[normal]: Le Moine Yang a rejoint -le groupe! [music][0x29][delay][0xc][end] +[bold]Yang[normal]: Le Moine Yang a rejoint le +groupe! [music][0x29][delay][0xc][end] T[end] @@ -1756,15 +1713,20 @@ Tiens-toi tranquille![new] T[end] -«Ha ha ha ha... Ainsi vous avez réussi à me vaincre... Toutefois... Je ne vais pas mourir si facilement... Je vais utiliser mon dernier souffle de vie pour vous emporter avec moi! Je vous attendrai en Enfer! Héhéheh!»[end] +«Ha ha ha ha... Ainsi vous avez réussi à +me vaincre... Toutefois... Je ne vais pas +mourir si facilement... Je vais utiliser mon +dernier souffle de vie pour vous +emporter avec moi! Je vous attendrai en +Enfer! Héhéheh!»[end] [bold]Tellah[normal]: Les murs![end] [bold]Cid[normal]: C'est fermé![music][0x23][new] [bold]Tellah[normal]: Cette porte aussi![end] [bold]Cecil[normal]: Palom! Porom![end] [bold]Palom[normal]: Ç'a été marrant, mon pote![new] -[bold]Porom[normal]: J'ai été honorée de -combattre à vos côtés![new] +[bold]Porom[normal]: J'ai été honorée de combattre +à vos côtés![new] [bold]Tellah[normal]: Que faites-vous, tous les deux![new] [bold]Palom[normal]: Nous ne pouvons pas vous @@ -1777,13 +1739,13 @@ Prenez soin de Cecil![end] [bold]Palom et Porom[normal]: ...ROC!![end] [bold]Cecil[normal]: Palom... Porom!!![music][0x2a][delay][0xc][end] -Ils se sont tous les deux pétrifiés par -leur propre volonté...[end] +Ils se sont tous les deux pétrifiés par leur +propre volonté...[end] [bold]Yang[normal]: Ils se sont sacrifiés...[end] [bold]Cid[normal]: C'est maintenant un combat de vengeance! -Lamentez-vous jusqu'à ce que je -ramène mon Entreprise![end] +Lamentez-vous jusqu'à ce que je ramène +mon Entreprise![end] [bold]Tellah[normal]: Quelle folie!! Laissez-moi voir ce que je peux faire... Esuna![end] @@ -1800,8 +1762,8 @@ Pas ces enfants![end] [bold]Cid[normal]: Ourg! La gravité est si forte, ici! -On pourra même pas remuer si on -porte des armures métalliques![new] +On pourra même pas remuer si on porte +des armures métalliques![new] [bold]Yang[normal]: Mes griffes, ça a l'air d'aller.[new] [bold]Tellah[normal]: Ne vous inquiétez pas! Nous avons toujours ma magie![end] @@ -1820,8 +1782,8 @@ Nous avons toujours ma magie![end] T[end] -[bold]Cecil[normal]: Si seulement je pouvais -utiliser mon épée...!![end] +[bold]Cecil[normal]: Si seulement je pouvais utiliser +mon épée...!![end] [bold]Cecil[normal]: Je comprends... Edward![end] [bold]Cecil[normal]: Scellé par le pouvoir magique @@ -1841,10 +1803,10 @@ côté de Mythidia, maintenant c'est impossible de passer.[new] En dessous d'ici se trouve la salle d'entraînement.[end] -Ainsi le sceau de Mythidia a été brisé -de leur côté![end] -La Route est scellée du côté de -Mythidia, alors tu ne peux pas l'utiliser.[end] +Ainsi le sceau de Mythidia a été brisé de +leur côté![end] +La Route est scellée du côté de Mythidia, +alors tu ne peux pas l'utiliser.[end] T[end] @@ -1860,12 +1822,11 @@ Mythidia, alors tu ne peux pas l'utiliser.[end] T[end] -[bold]Golbez[normal]: Ainsi, il a même tué -Cagnazzo... +[bold]Golbez[normal]: Ainsi, il a même tué Cagnazzo... Il est devenu bien plus fort.[new] [bold]Caïn[normal]: À propos du dernier cristal...[new] -[bold]Golbez[normal]: Je sais... ça va être délicat -de le récupérer où il est maintenant.[new] +[bold]Golbez[normal]: Je sais... ça va être délicat de +le récupérer où il est maintenant.[new] [bold]Caïn[normal]: Pourquoi n'envoies-tu pas Cecil le chercher pour toi?[new] [bold]Golbez[normal]: Je ne saisis pas très bien ce @@ -1884,23 +1845,20 @@ transmettre le message.[end] [bold]Rosa[normal]: Caïn![end] [bold]Caïn[normal]: Tu trouves encore que ton Cecil est supérieur à moi?[end] -[bold]Cecil[normal]: Si on était arrivé ne -serait-ce qu'une seconde plus tard... -cette guillotine aurait tranché Rosa -en deux![end] +[bold]Cecil[normal]: Si on était arrivé ne serait-ce +qu'une seconde plus tard... cette guillotine +aurait tranché Rosa en deux![end] -Mon père a trouvé un étrange minerai -ici. +Mon père a trouvé un étrange minerai ici. Son loisir, c'est de collectionner des queues d'animaux.[end] Qui êtes-vous? Allez-vous-en! -Par contre, si vous avez une queue, -c'est une autre affaire![end] -C...c'est la queue de rat que je -cherchais! -D'accord, je vais vous donner un bout -de ce minerai![new] +Par contre, si vous avez une queue, c'est +une autre affaire![end] +C...c'est la queue de rat que je cherchais! +D'accord, je vais vous donner un bout de +ce minerai! Obtenu l'Adamant![music][0x29][delay][0xc][end] C..c'est...la légendaire queue rose! D'accord, je vais aussi vous donner ça! @@ -1912,8 +1870,8 @@ Obtenu l'Armure d'Adamant![music][0x29][delay][0xc][end] [bold]FuSoYa[normal]: Monte près de sa bouche![new] [bold]Cid[normal]: Qui c'est, lui?[new] -[bold]Cecil[normal]: C'est FuSoYa, un homme -de la Lune.[new] +[bold]Cecil[normal]: C'est FuSoYa, un homme de +la Lune.[new] [bold]Cid[normal]: Un homme de la Lune?![new] [bold]FuSoYa[normal]: Peux-tu le faire?[new] [bold]Cid[normal]: Pour qui que tu me prends!? @@ -1987,8 +1945,8 @@ vie...[new] [bold]Barbariccia[normal]: Pour vous tuer![new] [bold]Rubicante[normal]: Nous nous rencontrons à nouveau! -Vous m'avez montré la puissance de -ceux qui unissent leurs forces![new] +Vous m'avez montré la puissance de ceux +qui unissent leurs forces![new] Maintenant, préparez-vous![end] [bold]Rubicante[normal]: Combattez-nous de toute votre force![end] @@ -2010,11 +1968,10 @@ C'est impossible...[end] T[end] -[bold]Yang[normal]: Et dire qu'elle était cachée -ici...[new] +[bold]Yang[normal]: Et dire qu'elle était cachée ici...[new] [bold]Tellah[normal]: Prodigieux![new] -[bold]Cid[normal]: Désolé de t'avoir fait -attendre, Entreprise! +[bold]Cid[normal]: Désolé de t'avoir fait attendre, +Entreprise! Allons-y![end] [bold]Cecil[normal]: C'est...!![end] @@ -2027,9 +1984,9 @@ C'est quoi, que tu veux?[end] soit à l'abri... elle l'est?[new] [bold]Caïn[normal]: Alors tu t'inquiètes vraiment pour ta petite pute, hein?[new] -Si tu veux la revoir... vivante... tu -devras l'échanger contre le cristal de la -terre de Troia.[new] +Si tu veux la revoir... vivante... tu devras +l'échanger contre le cristal de la terre de +Troia.[new] [bold]Cecil[normal]: Quoi!?[end] [bold]Tellah[normal]: Lâche![new] [bold]Caïn[normal]: Quand tu l'auras, je te @@ -2051,14 +2008,14 @@ sûr...[new] Oh, vous êtes humains![end] C'est ici que tous les survivants se cachent.[end] -C'est la route vers le quartier général -de Rubicante, la tour de Bab-Ilu.[end] +C'est la route vers le quartier général de +Rubicante, la tour de Bab-Ilu.[end] Nous avons perdu notre château... C'est notre maison, maintenant.[end] Nous sommes le fier peuple d'Eblana![end] Notre jeune maître est parti vérifier -quelque chose, mais ça fait bien -longtemps qu'il est parti... +quelque chose, mais ça fait bien longtemps +qu'il est parti... J'espère qu'il ne fait rien d'irréfléchi...[end] T[end] Il ne reste plus beaucoup de vivres. @@ -2066,13 +2023,13 @@ Je me demande combien de temps nous pourrons tenir...[end] Jeune maître, montre-nous ton Ninjutsu ultime![end] -Nous tiendrons ici jusqu'à ce que le -jeune maître rentre![end] +Nous tiendrons ici jusqu'à ce que le jeune +maître rentre![end] Notre jeune maître est parti seul en avant![end] -Quand le jeune maître se met en -colère, il devient très puissant...[end] +Quand le jeune maître se met en colère, il +devient très puissant...[end] Arrêtez notre jeune maître...[end] Notre jeune maître est parti à la @@ -2089,8 +2046,8 @@ maintenant![end] Le jeune maître va tuer l'ennemi, c'est sûr![end] -Quand le jeune maître était absent, le -roi et la reine ont été capturés...[end] +Quand le jeune maître était absent, le roi +et la reine ont été capturés...[end] Je vais protéger ma maman! Elle a mon petit frère ou ma petite sur dans son ventre![end] @@ -2107,8 +2064,7 @@ Bab-Ilu pour venger le roi et la Reine. Mais je m'inquiète pour lui. Il est sûrement encore parti trop loin...[end] Tiens bon, chérie![end] -D'où sont venus des monstres comme -ça?[end] +D'où sont venus des monstres comme ça?[end] Cet enfant est désespérant...[end] Le jeune maître a dit qu'il allait tuer les méchants! @@ -2121,8 +2077,8 @@ Si tu meurs aussi, Eblana va...[end] T[end] -[bold]Cid[normal]: Dès qu'on la sort tourner, -elle étale ce qu'elle sait faire! +[bold]Cid[normal]: Dès qu'on la sort tourner, elle +étale ce qu'elle sait faire! T'en dis quoi, poulette?[new] On va leur montrer ce que t'as dans le ventre![end] @@ -2184,11 +2140,11 @@ T[end] T[end] T[end] T[end] -Un misérable chevalier noir comme toi -ne peut même pas toucher la -marchandise que nous vendons ici![end] -Si tu revenais en un morceau, tu -pourras utiliser ces armes-là... mais c'est +Un misérable chevalier noir comme toi ne +peut même pas toucher la marchandise +que nous vendons ici![end] +Si tu revenais en un morceau, tu pourras +utiliser ces armes-là... mais c'est impossible.[end] Je t'ai déjà dit que tu ne pouvais pas utiliser.... un paladin? @@ -2197,8 +2153,7 @@ TOI...?[end] T[end] Je suis la plus belle de la ville! -Je suis trop petite pour que tu le -voies? +Je suis trop petite pour que tu le voies? Regarde de trèèèèès près![end] Laisse-moi te dire, avoir une belle fille, c'est rien que des embêtements! @@ -2268,8 +2223,8 @@ Vous êtes venus de la surface? Alors il y a vraiment un monde de surface après tout![end] Tu savais ça? -La grotte au nord-ouest mène au -Monde des Chimères. +La grotte au nord-ouest mène au Monde +des Chimères. C'est-y pas bizarre?[end] J'entends dire que l'océan à la surface est bleu... @@ -2283,8 +2238,7 @@ passe son temps à dormir, Lali.[end] Le maître a été vraiment occupé, Lali![end] Je vais devenir un forgeron aussi talentueux que le maître!![end] -Tu croyais que ç'allait être fini aussi -vite!? +Tu croyais que ç'allait être fini aussi vite!? Ne sois pas si impatient![end] C'est fait! L'épée sacrée Excalibur! @@ -2308,8 +2262,8 @@ elle était neuve![end] Tu as donné l'Épée Légendaire.[end] Zzz....[end] -Il y a des Sylphes dans la grotte qui -est loin dans le nord-ouest![end] +Il y a des Sylphes dans la grotte qui est +loin dans le nord-ouest![end] Les Sylphes sont si timides! Malgré que nous soyons gentils![end] @@ -2321,8 +2275,8 @@ Prenez tout ce que vous voulez![end] Je ne suis qu'un simple paysan.[end] Lali-ho![end] -C'est le château des Nains gouverné -par le roi Giotto![end] +C'est le château des Nains gouverné par +le roi Giotto![end] Golbez est un méchant! Mais vous, vous avez l'air chouette![end] Allez voir le roi Giotto![end] @@ -2345,17 +2299,16 @@ Ici, la pilosité faciale est un critère de beauté![end] Il y a peu de temps, le trou vers la surface s'est effondré! -Dans le même coin, nous avons sauvé -un drôle de vieux![new] +Dans le même coin, nous avons sauvé un +drôle de vieux![new] Il récupère à l'infirmerie![end] Je suis Luca! Mes poupées ont disparu. Vous ne les avez pas vues?[end] -La force des chars est la principale -force des Nains! -Nous ne serons pas vaincus si -facilement![end] +La force des chars est la principale force +des Nains! +Nous ne serons pas vaincus si facilement![end] Le roi a été vraiment très gentil avec Luca depuis que la reine est morte![end] Lali-ho! @@ -2376,13 +2329,13 @@ Golbez y est allé, mais ne vous inquiétez pas.[new] Sans la clef pour briser le sceau, personne ne peut y entrer.[new] -Par ailleurs, nous avons un plan -d'attaque, mais nous avons besoin de -votre assistance![new] +Par ailleurs, nous avons un plan d'attaque, +mais nous avons besoin de votre +assistance![new] [bold]Cecil[normal]: C'est notre faute si nous avons perdu le cristal! -S'il y a rien que nous puissions faire -pour aider...[new] +S'il y a rien que nous puissions faire pour +aider...[new] [bold]Giotto[normal]: Pendant que Golbez est occupé à la grotte scellée...[new] Pourriez-vous vous introduire dans la @@ -2393,31 +2346,27 @@ autres cristaux?[new] [bold]Giotto[normal]: Ne vous inquiétez pas! Je fais ordonner à la force des chars d'attaquer la tour![new] -Pendant notre diversion, entrez et -prenez les cristaux! -C'est notre seule chance, maintenant -que Golbez est parti![end] +Pendant notre diversion, entrez et prenez +les cristaux! +C'est notre seule chance, maintenant que +Golbez est parti![end] [bold]Caïn[normal]: Alors qu'est-ce qu'il faudrait faire?[new] -[bold]Rydia[normal]: C'est la base de l'ennemi, -non?[new] +[bold]Rydia[normal]: C'est la base de l'ennemi, non?[new] [bold]Rosa[normal]: Ça pourrait être assez dangereux.[new] -[bold]Yang[normal]: Mais vous savez ce qu'on -dit... +[bold]Yang[normal]: Mais vous savez ce qu'on dit... Qui ne tente rien n'a rien.[new] [bold]Caïn[normal]: Notre seule chance, c'est maintenant vu que Golbez est ailleurs.[new] [bold]Cecil[normal]: Très bien, alors...[end] [bold]Cecil[normal]: Nous le ferons![end] [bold]Giotto[normal]: Merci! -Il y a un passage secret sous le -château![new] +Il y a un passage secret sous le château! Normalement, c'est interdit, mais vous -pouvez l'utiliser! +pouvez l'utiliser![new] Je prie pour votre bonne fortune![end] -[bold]Giotto[normal]: Mes poupées étaient -maléfiques? +[bold]Giotto[normal]: Mes poupées étaient maléfiques? Je suis si furieuse que j'en crierais![end] [bold]Giotto[normal]: Nous allons tenir à distance le gros des forces ennemies! @@ -2428,11 +2377,11 @@ Le sort de toute chose est entre vos mains![end] [bold]Giotto[normal]: Papa dit que ce collier appartenait à ma mère, l'ancienne reine.[end] -[bold]Giotto[normal]: Près de la grotte scellée se -trouve la continent de Toméra où vivent -d'autres nains![new] -Mais on ne peut pas y aller à cause de -la lave![end] +[bold]Giotto[normal]: Près de la grotte scellée se trouve +la continent de Toméra où vivent d'autres +nains![new] +Mais on ne peut pas y aller à cause de la +lave![end] [bold]Giotto[normal]: Si vous pouvez voler, vous devriez pouvoir aller à la grotte scellée. Mais les Nains ne peuvent pas voler! @@ -2450,8 +2399,8 @@ Promettez-le![end] Gros Chocobo!? Grossier personnage!! On l'appelle l'Oiseau Dieu, ici![end] -Ici, apparaît un oiseau glorieux, il -gardera n'importe quoi pour toi![end] +Ici, apparaît un oiseau glorieux, il gardera +n'importe quoi pour toi![end] Personne ne peut franchir ce mur sans la permission du roi![end] Vous avez la permission du roi? @@ -2481,8 +2430,8 @@ Mais vous êtes encore plus courageux![end] Revenez en un morceau![end] Si ça devient trop dangereux, n'abusez pas de votre chance... fuyez![end] -Même si Golbez n'est pas dans la -tour de Bab-Ilu... le plus fort des quatre +Même si Golbez n'est pas dans la tour +de Bab-Ilu... le plus fort des quatre empereurs, Rubicante du Feu, y est encore![end] Notre force des chars va distraire @@ -2499,19 +2448,19 @@ utiliser?[end] C'est l'infirmerie![end] Parfois, même les nains se blessent![end] -Cet homme est vraiment énergique -pour un vieux râleur![end] +Cet homme est vraiment énergique pour +un vieux râleur![end] Quel vieux grincheux! -Il ne fait rien et se plaint de la -nourriture, mais il mange comme quatre![end] -Rien de tel qu'une bonne nuit de -sommeil pour se sentir mieux, Lali![end] +Il ne fait rien et se plaint de la nourriture, +mais il mange comme quatre![end] +Rien de tel qu'une bonne nuit de sommeil +pour se sentir mieux, Lali![end] Zzz...Zzz[end] Le corps de ce vieux n'est pas assez solide pour faire ça![end] -Si vous mettez de côté son -tempérament, ses plaintes et ses -ronflements, c'est un chouette gars![end] +Si vous mettez de côté son tempérament, +ses plaintes et ses ronflements, c'est un +chouette gars![end] Zzz... rrron ...Zzz[end] Ce vieux est surprenant![end] Les gens du monde du dessus sont très @@ -2584,15 +2533,14 @@ absence.[end] Ni le seigneur Golbez ni Rubicante ne sont là! C'est moi le patron, maintenant![new] -Je peux mener mes expériences en -paix...[new] +Je peux mener mes expériences en paix...[new] [bold]Rydia[normal]: Quel drôle de...[end] [bold]Docteur[normal]: Qui est là!!?[end] [bold]Caïn[normal]: Qu'est-ce que ça peut faire? Tu ferais mieux d'appeler de l'aide, doc. Rubicante n'est pas là pour te protéger![end] -[bold]Docteur[normal]: Vous ne me prenez -vraiment que pour un souffreteux? +[bold]Docteur[normal]: Vous ne me prenez vraiment +que pour un souffreteux? C'est moi le cerveau de toute cette opération![new] Je suis Lugeie! @@ -2620,23 +2568,20 @@ l'utiliser...[end] [bold]Hironobu Sakaguchi[normal]: Bienvenue![end] [bold]Hironobu Sakaguchi[normal]: Dessin des Cartes -[new] -[bold]Yasushi Matsumura[normal]: Eru, Naito, -Naoshi, Hoshiya, Kuwahara, ça faisait -longtemps! -Qu'est-ce qui ne va pas? ...Hein?[new] -Ce n'est pas les bonnes personnes!? +[bold]Yasushi Matsumura[normal]: Eru, Naito, Naoshi, +Hoshiya, Kuwahara, ça faisait longtemps! +Qu'est-ce qui ne va pas? ...Hein? +Ce n'est pas les bonnes personnes!?[new] Oups....[end] [bold]Yasushi Matsumura[normal]: Graphismes -[new] [bold]Masanori Hoshino[normal]: C'est moi qui ai -dessiné tous les monstres que tu -combats.[new] +dessiné tous les monstres que tu combats. S'il y en a un que tu préfères, dis-moi lequel![end] [bold]Masanori Hoshino[normal]: Je suis Taka, le -metteur de Points![new] -Dès que j'aurai fini ce jeu, je -deviendrai probablement un Super -Pointeur![end] +metteur de Points! +Dès que j'aurai fini ce jeu, je deviendrai +probablement un Super Pointeur![end] [bold]Masanori Hoshino[normal]: Graphismes -[new] [bold]Ryuko Tanaka[normal]: Ce sera ma toute dernière production. @@ -2665,9 +2610,9 @@ Dobashi -[new] de là! Je n'ai rien volé!![end] [bold]Kyoji Koizumi[normal]: Heh... -Si tu sais dès le début que tu n'as pas -de vacances, faire des jeux, ce n'est pas -si mal![new] +Si tu sais dès le début que tu n'as pas de +vacances, faire des jeux, ce n'est pas si +mal![new] Vous ne trouvez pas, Monsieur Sakaguchi?[end] @@ -2687,17 +2632,16 @@ J'ai fait plein de sons.[new] un penchant caché pour la musique. Je peux te jouer de la clarinette?[end] [bold]Nobuo Uematsu[normal]: Effets Sonores -[new] -[bold]Kenji Ito[normal]: Une fois que tu auras -terminé Final Fantasy IV, essaie Seiken -Densetsu![end] +[bold]Kenji Ito[normal]: Une fois que tu auras terminé +Final Fantasy IV, essaie Seiken Densetsu![end] Jusqu'ici, les jeux ne sont pas autorisés![end] Rosa et Rydia sont vraiment chaudes! Vous trouverez mes pouvoirs utiles![new] L'ingénieur du jeu Tokita Takahashi a -rejoint l'équipe![music][0x29][delay][0x28] Par pitié...prenez-moi -avec vous! +rejoint l'équipe![music][0x29][delay][0x28] Par pitié...prenez-moi avec +vous! Je n'en peux plus![music][0x2][end] Programme principal - [bold]Ken Narita[normal]: N'ajoutez plus @@ -2711,7 +2655,12 @@ l'université![end] c'est possible![end] [bold]Cecil[normal]: Aide-nous, Cid![end] -«Wahaha! Crevez, nains minables![end]Cecil: Vous n'irez pas plus loin![end]«Salopards! «Comment vous êtes entrés!? «Attrapez-les![end]«Merde! Tenez, prenez ça![end]«Maintenant, plus personne ne peut arrêter le super canon!»[end] +«Wahaha! Crevez, nains +minables![end]Cecil: Vous n'irez pas plus +loin![end]«Salopards! «Comment vous êtes +entrés!? «Attrapez-les![end]«Merde! Tenez, +prenez ça![end]«Maintenant, plus personne ne +peut arrêter le super canon!»[end] [bold]Cecil[normal]: Merde![new] [bold]Caïn[normal]: Bon Dieu![end] [bold]Cecil[normal]: Yang![new] @@ -2742,10 +2691,9 @@ On compte sur toi, mon pote![end] Tu es devenu un si formidable paladin! On ne s'est vraiment pas trompé en t'aidant, alors![end] -Le sort de tout ce qui vit sur cette -terre repose entre tes mains![end] -Battez-vous pour moi... et pour -Tellah![end] +Le sort de tout ce qui vit sur cette terre +repose entre tes mains![end] +Battez-vous pour moi... et pour Tellah![end] Cela doit être ta destinée que de te confronter à cela. Je prie pour ta survie![end] @@ -2754,7 +2702,8 @@ preniez pas avec vous! Vraiment... Écoutez, vous![new] Vous revenez vivant![end] -«Parce que si tu n'est pas dans le coin, le patron fait la tronche!»[end] +«Parce que si tu n'est pas dans le coin, le +patron fait la tronche!»[end] M. Cecil, revenez bientôt![end] Prince Edward pense tout le temps à vous![end] @@ -2776,12 +2725,12 @@ souterrain![end] T[end] Rydia, tu es de retour![end] -À l'exception de Rydia, vous êtes -les premiers humains à venir ici.[end] +À l'exception de Rydia, vous êtes les +premiers humains à venir ici.[end] C'est le Monde des Chimères. Le monde où les Chimères vivent.[end] -Le roi des Chimères vit au plus profond -de notre monde.[end] +Le roi des Chimères vit au plus profond de +notre monde.[end] T[end] @@ -2790,9 +2739,9 @@ Le monde des Chimères est dirigé par Asura et le roi des Chimères.[end] J'entends dire que nos copains dans l'autre monde ne se tiennent pas bien.[end] -On dit que si vous ne pouvez pas -vaincre Dame Asura, le roi ne t'écoutera -même pas![end] +On dit que si vous ne pouvez pas vaincre +Dame Asura, le roi ne t'écoutera même +pas![end] «Lut, Rydia! Quoi? C'est bizarre que nous parlions?[end] @@ -2808,20 +2757,18 @@ Ces gens sont tes amis?[end] Ne repars plus jamais![end] Shh!! -Silence, vous êtes dans une -bibliothèque![end] +Silence, vous êtes dans une bibliothèque![end] Hmm....vais-je aimer ce livre...je me le demande?[end] Le géant qui secoue la terre, Titan... Avec sa force, il déchire la terre... et -toutes les créatures seront aspirées -dans l'abîme qu'il aura créé.[end] +toutes les créatures seront aspirées dans +l'abîme qu'il aura créé.[end] Le démon du Feu, Ifrit... On dit que son feu peut consumer n'importe quoi.[end] -Il paraît qu'il y a des magies -d'invocation dont personne n'a encore -entendu parler...[end] +Il paraît qu'il y a des magies d'invocation +dont personne n'a encore entendu parler...[end] Le doux vieil homme Ramuh... Long à la colère, prompt à juger... Il appelle des nuages de tempêtes et de @@ -2832,10 +2779,10 @@ geler le cur.[end] Chocobo... La plus adorable des Chimères![end] La magie d'invocation... -La magie qui appelle les Chimères de -leur royaume mystique...[new] -Ceux qui possèdent ce pouvoir sont -très peu nombreux.[end] +La magie qui appelle les Chimères de leur +royaume mystique...[new] +Ceux qui possèdent ce pouvoir sont très +peu nombreux.[end] Le monde des Chimères a une histoire tellement plus longue que le monde des humains...[end] @@ -2853,53 +2800,50 @@ Y a-t-il aussi de la littérature dans le monde des humains?[end] On ne s'ennuie jamais, ici. -Il y a tellement de livres qu'il faudrait -une éternité pour tous les lire![end] -Pour les monstres sur lesquels[new] +Il y a tellement de livres qu'il faudrait une +éternité pour tous les lire![end] +Pour les monstres sur lesquels «Épier»[new] ne marche pas... le Dictionnaire des -Monstres montrera leur véritable -nature....[end] +Monstres montrera leur véritable nature....[end] Chimère, Monstre, Humain... D'où sont-ils venus et où vont-ils.... Le mystère de l'éternité...[end] Il y a bien longtemps, un immense vaisseau est venu de la Lune sur Terre... -Maintenant, il dort au fond du ventre -d'un dragon.[end] +Maintenant, il dort au fond du ventre d'un +dragon.[end] Pour celui qui surpasse le roi Chimère... Il est dit qu'il existe un dieu Chimère qui -nous a créés et qui nous protège de -loin.[new] -Il ne connaît pas la défaite... +nous a créés et qui nous protège de loin. +Il ne connaît pas la défaite...[new] Seule sa propre puissance retournée contre lui pourrait lui faire du mal...[end] Il y a deux lunes... -Mais on dit que dans les temps anciens, -il n'y en avait qu'une seule.[end] -La Reine du Monde des Chimères, -Asura... -En tant qu'épouse du roi Chimère, elle -est la clef vers son audience.[new] +Mais on dit que dans les temps anciens, il +n'y en avait qu'une seule.[end] +La Reine du Monde des Chimères, Asura... +En tant qu'épouse du roi Chimère, elle est +la clef vers son audience.[new] Seuls ceux qui peuvent la surpasser pourront voir la vraie forme du roi...[end] Le roi Chimère... Il est apparu dans l'océan du nord. -On dit de lui qu'il est maître des -océans et sans rival.[end] +On dit de lui qu'il est maître des océans +et sans rival.[end] Odin, le chevalier des grands guerriers du passé...[new] La seule fois qu'il a jamais été vaincu, -c'était quand un éclair s'est abattu sur -son épée.[end] +c'était quand un éclair s'est abattu sur son +épée.[end] Les douces et sveltes Sylphes... Quand elles unissent leurs forces, elles -canalisent l'énergie vitale de leurs -ennemis vers elles-mêmes....[end] +canalisent l'énergie vitale de leurs ennemis +vers elles-mêmes....[end] La loi du Monde des Chimères... ...est d'avoir de la force et un cur pur... -Affirmez cette force, et testez leur -âme par un combat![end] +Affirmez cette force, et testez leur âme +par un combat![end] C'est la salle du roi et de la reine des Chimères.[end] @@ -2908,8 +2852,8 @@ besoin de la permission de la reine Asura.[end] Rydia... Tu as des amis forts et bienveillants. Tu peux m'appeler n'importe quand...[end] -Tu possèdes une lumière puissante qui -te guide! +Tu possèdes une lumière puissante qui te +guide! Je vais te donner mes pouvoirs en tant que maître des océans, Léviathan![end] Le roi Chimère? @@ -2917,8 +2861,8 @@ Non, non, je ne suis qu'un vieux fou![end] Alors je vais tester ta force![end] Alors, malheureusement, je ne peux pas vous donner mon pouvoir.[end] -Une fois que tu auras confiance en toi, -je te combattrai quand tu voudras![end] +Une fois que tu auras confiance en toi, je +te combattrai quand tu voudras![end] Est-ce que les humains peuvent utiliser les armes, ici?[end] @@ -2933,8 +2877,8 @@ Nous voulons juste vivre en paix.[end] Ils vivent tous ici...[end] Cet Ifrit! Une tête brûlée, comme toujours.[end] -Si tu lances le sort Lévite, tu -échapperas à la colère de Titan![end] +Si tu lances le sort Lévite, tu échapperas +à la colère de Titan![end] T[end] @@ -2957,8 +2901,8 @@ Tout de suite![end] [bold]Yang[normal]: N'emportez pas Yang![end] [bold]Yang[normal]: Nous ne vous laisserons pas Yang![end] -[bold]Yang[normal]: Vous, les humains, vous êtes -si violents![end] +[bold]Yang[normal]: Vous, les humains, vous êtes si +violents![end] [bold]Yang[normal]: Nous l'avons trouvé évanoui au-dehors de notre trou. Mais il ne s'est pas réveillé... @@ -2975,14 +2919,14 @@ M. Cecil?[new] [bold]Cecil[normal]: Yang![new] [bold]Rydia[normal]: Je suis si contente que tu ailles bien![new] -[bold]Yang[normal]: Les Sylphes m'ont arraché -aux griffes de la mort.[new] +[bold]Yang[normal]: Les Sylphes m'ont arraché aux +griffes de la mort.[new] [bold]Rosa[normal]: Grâce à toi, le super canon a été détruit![new] [bold]Yang[normal]: Je viens avec vous...[new] [bold]Sylphe[normal]: Non, tu dois dormir![end] -[bold]Yang[normal]: Le sort du monde est en -train de se jouer! +[bold]Yang[normal]: Le sort du monde est en train +de se jouer! Je ne peux pas rester ici et dormir![new] [bold]Edge[normal]: Ce n'est pas un endroit pour un mec blessé comme toi.[end] @@ -3006,8 +2950,7 @@ Rydia a appris Sylphe![music][0x29][delay][0xc][end] [bold]Sylphe[normal]: Ah! Arrêtez![end] [bold]Sylphe[normal]: Yang va beaucoup mieux![end] -[bold]Sylphe[normal]: C'est bien vide sans -Yang...[end] +[bold]Sylphe[normal]: C'est bien vide sans Yang...[end] [bold]Sylphe[normal]: Il est marié, alors.... enfin bon![end] [bold]Sylphe[normal]: Dites bonjour à Yang de notre part![end] @@ -3073,36 +3016,34 @@ puissance, tu peux appeler mon nom![end] T[end] Nous sommes les cristaux de la Lune.[end] -L'équilibre des huit cristaux sur la -Planète Bleue est maintenu ici sur la -Lune.[end] +L'équilibre des huit cristaux sur la Planète +Bleue est maintenu ici sur la Lune.[end] Les gens de la Lune dorment loin au-dessous de ce sol. FuSoYa est le gardien des dormeurs.[end] Zémus est un homme terrible. -Bien qu'il soit scellé profondément sous -le sol, son esprit maléfique ne cesse de +Bien qu'il soit scellé profondément sous le +sol, son esprit maléfique ne cesse de s'accroître...[end] Seul notre pouvoir garde Zémus scellé dans le noyau de la lune.[end] Zémus a utilisé Golbez pour réunir les -cristaux de la Planète Bleue... et a -amplifié leur puissance avec la tour de -Bab-Ilu.[end] +cristaux de la Planète Bleue... et a amplifié +leur puissance avec la tour de Bab-Ilu.[end] Dès à présent, nous sentons ses tentatives pour détruire le sceau.[end] Le sol du centre de la salle mène au noyau de la lune... le royaume de Zémus...[end] -Quand la tour de Bab-Ilu a été -détruite, notre sceau a été affaibli![end] -Dormant avec les Luniens, au-dessous, -se trouvent des armes puissantes.[end] +Quand la tour de Bab-Ilu a été détruite, +notre sceau a été affaibli![end] +Dormant avec les Luniens, au-dessous, se +trouvent des armes puissantes.[end] Il y a déjà quelque temps que FuSoYa et le fils de KluYa sont entrés et descendus.[end] -Nous utilisons toute notre puissance -pour essayer de maintenir Zémus scellé... -au plus profond du noyau lunaire.[end] +Nous utilisons toute notre puissance pour +essayer de maintenir Zémus scellé... au +plus profond du noyau lunaire.[end] Il y a une énergie phénoménale qui transite entre Zémus et nous.[end] J'ai peur pour FuSoYa et le fils de @@ -3144,9 +3085,9 @@ des surnoms...[end] T[end] Tu as obtenu la Masamune![music][0x29][delay][0xc][end] -Pensiez-vous réellement que des gens -de la Planète Bleue pourraient être -capables d'utiliser cette... +Pensiez-vous réellement que des gens de +la Planète Bleue pourraient être capables +d'utiliser cette... Masamune!?[end] T[end] diff --git a/text/fr/battle_messages.xml b/text/fr/battle_messages.xml index 945ac3c..c6cd0a4 100644 --- a/text/fr/battle_messages.xml +++ b/text/fr/battle_messages.xml @@ -2,7 +2,7 @@ Le dragon a changé de forme en brouillard ![end] -Il reprend sa forme ! C'est le moment d’attaquer ![end] +Il reprend sa forme ! C'est le moment d'attaquer ![end] Le brouillard annule toutes les attaques ![end] @@ -44,19 +44,19 @@ S'il vous plaît ! Arrêtez tous les deux ![end] -Tella: Toi, comment oses-tu faire du mal à ma fille‥‥[end] +Tella: Toi, comment oses-tu faire du mal à ma fille...[end] -C'est faux ![end] +Barde: C'est faux ![end] Tella: Qu'est-ce qui est faux ?![end] -Veuillez écouter ce que j'ai à dire ![end] +Barde: Veuillez écouter ce que j'ai à dire ![end] Tella: Tais-toi ![end] -Barde:Je vous en prie ![end] +Barde: Je vous en prie ![end] -Tell: Cette douleur, c'est la douleur d'Anna...[end] +Tella: Cette douleur, c'est la douleur d'Anna...[end] Anna... qu'est-ce que...[end] @@ -368,7 +368,7 @@ La prochaine fois, je serai papa. Ahhh.[end] -C’est bon, non ?[end] +C'est bon, non ?[end] À plus, alors. Ahhh.[end] diff --git a/text/fr/battle_text.xml b/text/fr/battle_text.xml index 304b280..6eb9059 100644 --- a/text/fr/battle_text.xml +++ b/text/fr/battle_text.xml @@ -5,10 +5,10 @@ Attaque préventive ![end] Attaque surprise ![end] Attaque par-derrière ![end] - Il s’est enfui[end] + Il s'est enfui[end] Victoire en combat ![end] Je me souviens ![end] - Non, ce n’est pas ça[end] + Non, ce n'est pas ça[end] Hélas, je ne me souviens de rien[end] Je ne peux pas parler[end] Chanson des grenouilles[end] @@ -16,7 +16,7 @@ Chanson de séduction[end] Chanson du silence[end] Pas assez de potions.[end] - La prière n’a pas atteint le ciel[end] + La prière n'a pas atteint le ciel[end] La synchronisation est perturbée[end] Magie augmentée ![end] Monstre paniqué[end] @@ -56,6 +56,6 @@ Dégâts de poison[end] PV régénérés[end] [0x6]0 Gils tombés![end] - “Peu à peu, l’énergie s’est épuisée et la force a disparu.[end] - Force concentrée, puissance d’attaque doublée ![end] + “Peu à peu, l'énergie s'est épuisée et la force a disparu.[end] + Force concentrée, puissance d'attaque doublée ![end] diff --git a/text/fr/item_descriptions.xml b/text/fr/item_descriptions.xml index d21eab8..2a39cd9 100644 --- a/text/fr/item_descriptions.xml +++ b/text/fr/item_descriptions.xml @@ -1,9 +1,9 @@ Ne peut pas être utilisé depuis ce menu. - Restaure des HP. - Restaure des MP. - Restaure complètement les HP/MP. + Restaure des PV. + Restaure des PM. + Restaure complètement les PV/PM. Guérit l'incapacité de combattre. Guérit la pétrification. Guérit le statut de grenouille. @@ -14,7 +14,7 @@ Neutralise le poison. Enlève la malédiction. Guérit divers états. - Régénère 1000 HP et 100 MP à l'équipe[0x01][0xd4][0x00]et guérit des altérations d'état. + Régénère 1000 PV et 100 PM à l'équipe[0x01][0xd4][0x00]et guérit des altérations d'état. Revient à l'étape précédente. Téléporte à la surface. Affichez la carte de la région. diff --git a/text/fr/monsters_long.xml b/text/fr/monsters_long.xml new file mode 100644 index 0000000..07261ec --- /dev/null +++ b/text/fr/monsters_long.xml @@ -0,0 +1,227 @@ + + +Gobelin +Basilic +Aigle plongeur +Orbe flottant +Insectus +Chauve-visage +Yeux des bois +Rat-épée +Mini-magicien +Sahuagin désert +Œil volant +Jambe-main +Ver des sables +Gigantoad +Coquille à crocs +Zombie +Tue-mouches +Fleur de sang +Crapaud organique +Guimauve rouge +Gelée jaune +Sahuagin +Lacey +Chrysalide +Gobelin casqué +Lézard noir +Tortue d'adamant +Domo Boy +Bavarois violet +Soldat de Baron +Général +Gatling +Petit tueur +Belle de mort +Esprit +Squelette +Cocatrice +Gargouille +Bébé Rudra +Belphegor +Zu +Shiva +Alligator +Éclabousseur +Marine de Baron +Capitaine +Âme +Os sanglant +Goule +Jarre-crâne +Revenant +Dame Dracula +Ahriman +Dragon squelette +Poisson-éclair +Gigantogator +Hydre +Ver d'inondation +Élite de Baron +Lamia +Aiguille infernale +Serpent jumeau +Esprit de foudre +Flagelleur mental +Naga +Ogre +Cait Sith +Chevalier noir +Chevalier centaure +Demoiselle vampire +Marionnettiste +Marionnette +Aile funeste +Filet de mort +Marid +Chevalier diable +Mammouth blindé +Dame gardienne +Chevalier spectral +Naga raja +Méduse +Zombie saurus +Tortue de magma +Diablotin +Cauchemar +Bombe +Mini-bombe +Chimère +Tortue des enfers +Robe de fer +Chien de feu +Gorgone +Golem de pierre +Lilith +Mère lamia +Crapaud servile +Taupes +Rudra +Sorcier +Ogre berserker +Pot fraudeur +Chauve-sang +Alchimiste +Chevalier de feu +Canon mécanique +Bombe soignante +Grenade noire +Fléau +Bras ultime +Coeurl +Dragon mécanique +Alraune +Praticien +Grands-fonds +Ver des abysses +Rouge sanglant +Demoiselle leader +Lézard glacial +Batteur infernal +Tête démoniaque +Bête des vents +Invocateur +Dame sorcière +Porte d'assaut +Sorcière crapaud +Mammon +Cerveau chimère +Virus lunaire +Souffle de Zemus +Mousse blanche +Flan noir +Esprit de Zemus +Golem de mithril +Dragon vert +Princesse flan +Yeux +Soldat mécanique +Soldat géant +Déesse de la lune +Morbol +Dragon d'argent +Dragon jaune +Satan junior +Eucaryote +Phase +Soldat de fer +Soldat démoniaque +Golem d'acier +Ahriman +Lunasaurus +Chercheur +Nécromancien +Bahamut noir +Procaryote +Tiamat +Dragon bleu +Dragon d'or +Dragon de foudre +Dragon blanc +Dragon rouge +Béhémoth +Dragon de brume +Octomammoth +Fourmilion +Mère bombe +Scarmiglione +Scarmiglione +Baigan + Bras droit + Bras gauche +Cagnazzo +Elfe noir +Elfe noir +Dog +Mag +Rag +Golbez +Barbariccia +Calco +Calcabrina +Golbez +Dragon noir +Docteur +Barnabas +Dr. Lugae +Roi d'Eblan +Reine d'Eblan +Rubicante +Odin +Léviathan +Bahamut +Mur des démons +Asura +Quatre archifiends +Quatre archifiends +Dragon noir +Sahuagin +Sys. de contrôle +Sys. de défense +Zemus +Zeromus +Zeromus +Chevalier dragon +Barde lunaire +Moine +Chevalier noir +Petite fille +Titan +Orbe flottant +Zu +Brina +Skulnant +Mecha fusionné +Système d'attaque +Monstre 214 +Higuchi Katsuhisa +Zeromus +Itou Hiroyuki +Matsui Akihiko +Aoki Kazuhiko +Nakada Hiromi +Yoshii Kiyoshi +Takahashi Tetsuya +Mistéleg + \ No newline at end of file diff --git a/text/fr/places-names.xml b/text/fr/places-names.xml index bc3c528..90bfedf 100644 --- a/text/fr/places-names.xml +++ b/text/fr/places-names.xml @@ -47,8 +47,8 @@ Underground Waterfall Château de Damcyan Donjon de Damcyan - Sous-sol de l’Antlion - Étage 1 - Nid de l’Antlion + Sous-sol de l'Antlion - Étage 1 + Nid de l'Antlion Mont Hobs - Ouest Summit Fabul @@ -68,12 +68,12 @@ Village de Toroia Salle de Développement Ferme de Chocobos Noirs - Village d’Agalt + Village d'Agalt Tour des Étoiles Observatoire Grotte du Pouvoir - Château d’Eblana - Grotte d’Eblana + Château d'Eblana + Grotte d'Eblana Tour de Babil - Niveau 1 Tour de Zott Bouche du Géant @@ -117,8 +117,8 @@ Cou du Géant Poitrine du Géant Estomac du Géant - Passage à l’intérieur du Géant - À l’intérieur du Géant + Passage à l'intérieur du Géant + À l'intérieur du Géant Poumon du Géant Système de Contrôle Grotte des Sélénites diff --git a/utils/__init__.py b/utils/__init__.py index cd04ff3..e69de29 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1 +0,0 @@ -__author__ = 'emmanuel' diff --git a/utils/dakutens.py b/utils/dakutens.py index c85db70..12e6993 100644 --- a/utils/dakutens.py +++ b/utils/dakutens.py @@ -5,16 +5,13 @@ def generate_dakutens(table: Table) -> bytes: - accents = set() - accents_mapping = { - ' ̀': b"\x8a", ' ̈': b"\x8d", ' ̂': b"\x8b", ' ́': b"\x8c" - } + accents_mapping = {" ̀": b"\x8a", " ̈": b"\x8d", " ̂": b"\x8b", " ́": b"\x8c"} dakutens = [b"\x00\00"] * 256 count = 0 - lowest = 0xff + lowest = 0xFF highest = 0 for key in table.lookup.keys(): @@ -22,14 +19,18 @@ def generate_dakutens(table: Table) -> bytes: font_char = table.to_bytes(key)[0] if len(normalized) > len(key): - if normalized[1] == 0xcc and normalized[2] != 0xa7: + if normalized[1] == 0xCC and normalized[2] != 0xA7: print(key) lookup_key = (b"\x20" + normalized[1:]).decode("utf-8") - non_accentuated_char = table.to_bytes(normalized[:1]. decode("utf-8")) + non_accentuated_char = table.to_bytes(normalized[:1].decode("utf-8")) lowest = min(lowest, font_char) highest = max(highest, font_char) - dakutens[font_char] = accents_mapping[lookup_key] + non_accentuated_char + dakutens[font_char] = accents_mapping[lookup_key] + non_accentuated_char count += 1 - return struct.pack(" np.n x_offset = column * char_width y_offset = line * char_height - return image[y_offset:y_offset + char_height, x_offset:x_offset + char_width] + return image[y_offset : y_offset + char_height, x_offset : x_offset + char_width] def char_as_1bbp(char): binary_data = [] for byte in char: - byte_value = int(''.join(byte.astype(str)).ljust(8, '0'), 2) + byte_value = int("".join(byte.astype(str)).ljust(8, "0"), 2) binary_data.append(byte_value) return bytes(binary_data) @@ -38,7 +38,7 @@ def char_as_1bbp(char): def get_max_width(char: np.ndarray) -> int: max_width = 0 for byte in char: - trimmed = np.trim_zeros(byte, 'b') + trimmed = np.trim_zeros(byte, "b") max_width = max(len(trimmed), max_width) return max_width @@ -51,7 +51,7 @@ def convert_font_to_1bpp(font_file, has_grid=True, char_height=16): char = get_char(image, 0x00, has_grid, 8, char_height) - data = b'' + data = b"" char_index = 1 while len(char) > 0: data += char_as_1bbp(char) @@ -64,6 +64,7 @@ def convert_font_to_1bpp(font_file, has_grid=True, char_height=16): return len_table, data + def convert_font_to_2bpp(font_file, has_grid=True, char_height=16): image = np.array(Image.open(font_file)) @@ -71,7 +72,7 @@ def convert_font_to_2bpp(font_file, has_grid=True, char_height=16): char = get_char(image, 0x00, has_grid, 8, char_height) - data = b'' + data = b"" char_index = 1 while len(char) > 0: data += write_as_2bpp(char) @@ -106,20 +107,20 @@ def remove_grid(font_file): im = Image.fromarray(np.uint8(font * 255)) # output = io.BytesIO() - im.save('/tmp/font.png', format='PNG') + im.save("/tmp/font.png", format="PNG") -if __name__ == '__main__': - remove_grid('/Users/emmanuel/PycharmProjects/ff4/fonts/wicked_vwf.png') +if __name__ == "__main__": + remove_grid("/Users/emmanuel/PycharmProjects/ff4/fonts/wicked_vwf.png") def write_as_2bpp(data: np.ndarray) -> bytearray: binary_data = bytearray() for y_value in range(0, len(data[0]), 8): - char = data[0:8, y_value:y_value + 8] + char = data[0:8, y_value : y_value + 8] for byte in char: - byte_value = int(''.join(byte.astype(str)).ljust(8, '0'), 2) + byte_value = int("".join(byte.astype(str)).ljust(8, "0"), 2) binary_data.append(0xFF) binary_data.append(byte_value) diff --git a/utils/font_converter.py b/utils/font_converter.py index abbd4f3..2812cb2 100644 --- a/utils/font_converter.py +++ b/utils/font_converter.py @@ -4,17 +4,23 @@ class FontConverter: - def __init__(self, font_file: str, has_grid: bool = False, char_width: int = 8, char_height: int = 16) -> None: + def __init__( + self, + font_file: str, + has_grid: bool = False, + char_width: int = 8, + char_height: int = 16, + ) -> None: self.font_file = font_file self.has_grid = has_grid self.char_width = char_width self.char_height = char_height self.image: Optional[np.ndarray] = None - + def _load_image(self) -> None: if self.image is None: self.image = np.array(Image.open(self.font_file)) - + def get_char(self, char: int) -> np.ndarray: self._load_image() shape = self.image.shape @@ -38,7 +44,10 @@ def get_char(self, char: int) -> np.ndarray: x_offset = column * self.char_width y_offset = line * self.char_height - return self.image[y_offset : y_offset + self.char_height, x_offset : x_offset + self.char_width] + return self.image[ + y_offset : y_offset + self.char_height, + x_offset : x_offset + self.char_width, + ] def char_as_1bbp(self, char: np.ndarray) -> bytes: binary_data = [] @@ -55,12 +64,14 @@ def get_max_width(self, char: np.ndarray) -> int: return max_width - def convert_to_1bpp(self, width_overrides: dict[int, int]) -> tuple[dict[int, int], bytes]: + def convert_to_1bpp( + self, width_overrides: dict[int, int] + ) -> tuple[dict[int, int], bytes]: self._load_image() data = b"" char_index = 0 - while char_index <= 0xff: + while char_index <= 0xFF: char = self.get_char(char_index) data += self.char_as_1bbp(char) @@ -138,154 +149,341 @@ def _get_char_bounds(self, char_data: np.ndarray) -> tuple[int, int]: rows_with_pixels = np.any(char_data > 0, axis=1) if not np.any(rows_with_pixels): return 0, self.char_height - 1 - + top_row = np.argmax(rows_with_pixels) bottom_row = len(rows_with_pixels) - 1 - np.argmax(rows_with_pixels[::-1]) return top_row, bottom_row - - def _check_collision(self, char1_data: np.ndarray, char2_data: np.ndarray, - char2_start_pos: int, overlap_top: int, overlap_bottom: int) -> bool: - """Check if characters collide at given position.""" + + def _count_touches( + self, + char1_data: np.ndarray, + char2_data: np.ndarray, + char2_start_pos: int, + overlap_top: int, + overlap_bottom: int, + ) -> tuple[int, int]: + """Count diagonal and orthogonal touches between two characters separately.""" char1_width = char1_data.shape[1] char2_width = char2_data.shape[1] - - for row in range(overlap_top, overlap_bottom + 1): + char1_height = char1_data.shape[0] + + # Calculate total width for the combined render + total_width = max(char1_width, char2_start_pos + char2_width) + + # Create a combined render and track ownership + combined = np.zeros((char1_height, total_width), dtype=np.uint8) + ownership = np.zeros( + (char1_height, total_width), dtype=np.uint8 + ) # 1=char1, 2=char2 + + # Place char1 first + for row in range(char1_data.shape[0]): + for col in range(char1_data.shape[1]): + if char1_data[row, col] > 0: + combined[row, col] = char1_data[row, col] + ownership[row, col] = 1 + + # Place char2, only overwriting with non-zero pixels + for row in range(char2_data.shape[0]): + for col in range(char2_data.shape[1]): + if char2_data[row, col] > 0: # Only place non-zero pixels + result_col = char2_start_pos + col + if result_col < total_width: + combined[row, result_col] = char2_data[row, col] + ownership[row, result_col] = 2 + + # Count diagonal and orthogonal touches separately + diagonal_pairs = set() + orthogonal_pairs = set() + + for row in range(char1_height): + for col in range(total_width): + if combined[row, col] == 1: + pixel_owner = ownership[row, col] + + # Check diagonal directions + for dr, dc in [(1, 1), (1, -1), (-1, 1), (-1, -1)]: + new_row, new_col = row + dr, col + dc + if ( + 0 <= new_row < char1_height + and 0 <= new_col < total_width + and combined[new_row, new_col] == 1 + ): + neighbor_owner = ownership[new_row, new_col] + + # Only count touches between different characters + if ( + pixel_owner != neighbor_owner + and pixel_owner > 0 + and neighbor_owner > 0 + ): + # Create a unique key for this touch pair to avoid double counting + touch_key = tuple( + sorted([(row, col), (new_row, new_col)]) + ) + diagonal_pairs.add(touch_key) + + # Check orthogonal directions + for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]: + new_row, new_col = row + dr, col + dc + if ( + 0 <= new_row < char1_height + and 0 <= new_col < total_width + and combined[new_row, new_col] == 1 + ): + neighbor_owner = ownership[new_row, new_col] + + # Only count touches between different characters + if ( + pixel_owner != neighbor_owner + and pixel_owner > 0 + and neighbor_owner > 0 + ): + # Create a unique key for this touch pair to avoid double counting + touch_key = tuple( + sorted([(row, col), (new_row, new_col)]) + ) + orthogonal_pairs.add(touch_key) + + return len(diagonal_pairs), len(orthogonal_pairs) + + def _check_collision( + self, + char1_data: np.ndarray, + char2_data: np.ndarray, + char2_start_pos: int, + overlap_top: int, + overlap_bottom: int, + ) -> bool: + """Check for direct collisions (overlapping pixels).""" + char1_width = char1_data.shape[1] + char2_width = char2_data.shape[1] + char1_height = char1_data.shape[0] + + # Check for direct pixel overlap + for row in range(char1_height): for char2_col in range(char2_width): char2_pixel_pos = char2_start_pos + char2_col - - if 0 <= char2_pixel_pos < char1_width and char2_data[row, char2_col] > 0: - # Direct collision - if char1_data[row, char2_pixel_pos] > 0: - return True - - # Check immediate left diagonal (prevents char2 from getting too close to horizontal bars) - if (char2_pixel_pos > 0 and - char1_data[row, char2_pixel_pos - 1] > 0): - return True + + if ( + 0 <= char2_pixel_pos < char1_width + and char1_data[row, char2_pixel_pos] == 1 + and char2_data[row, char2_col] == 1 + ): + return True + return False - def compute_kerning(self, char1_index: int, char2_index: int, default_kerning: int = 1) -> int: - """Compute optimal kerning between two characters.""" + def compute_kerning( + self, char1_index: int, char2_index: int, default_kerning: int = 1 + ) -> int: + """Compute optimal kerning between two characters, targeting exactly 1 touch.""" self._load_image() - + char1_data = self.get_char(char1_index) char2_data = self.get_char(char2_index) - + char1_width = self.get_max_width(char1_data) trimmed_char1 = char1_data[:, :char1_width] - trimmed_char2 = char2_data[:, :self.get_max_width(char2_data)] - + trimmed_char2 = char2_data[:, : self.get_max_width(char2_data)] + char1_top, char1_bottom = self._get_char_bounds(trimmed_char1) char2_top, char2_bottom = self._get_char_bounds(trimmed_char2) - + overlap_top = max(char1_top, char2_top) overlap_bottom = min(char1_bottom, char2_bottom) - - max_kerning_reduction = 0 + + # Try kerning values from most aggressive to most conservative + best_kerning = default_kerning max_reduction_limit = max(1, default_kerning) + char1_width - + for reduction in range(1, max_reduction_limit + 1): - char2_start_pos = char1_width + default_kerning - reduction - - # Only check collision if there's vertical overlap + # Calculate the actual position used in rendering (kerning + 1) + kerning = default_kerning - reduction + actual_spacing = kerning + 1 + char2_start_pos = char1_width + actual_spacing + + # Check for direct collisions (forbidden) if overlap_top <= overlap_bottom: - if self._check_collision(trimmed_char1, trimmed_char2, char2_start_pos, overlap_top, overlap_bottom): + if self._check_collision( + trimmed_char1, + trimmed_char2, + char2_start_pos, + overlap_top, + overlap_bottom, + ): break - max_kerning_reduction = reduction - + + # Count diagonal and orthogonal touches separately + diagonal_touches, orthogonal_touches = self._count_touches( + trimmed_char1, + trimmed_char2, + char2_start_pos, + overlap_top, + overlap_bottom, + ) + + # Reject if any orthogonal touches (horizontal/vertical adjacency not allowed) + if orthogonal_touches > 0: + continue + + # Target exactly 1 diagonal touch as optimal + if diagonal_touches == 1: + return kerning + elif diagonal_touches == 0: + # 0 diagonal touches is also acceptable, save as fallback + best_kerning = kerning + # If diagonal_touches > 1, this kerning is too aggressive, continue to less aggressive values + # When default_kerning is 0, try negative kerning (overlapping) - if default_kerning == 0 and max_kerning_reduction == 0: + if default_kerning == 0 and best_kerning == default_kerning: for overlap_pixels in range(1, char1_width): - char2_start_pos = char1_width - overlap_pixels - if overlap_top > overlap_bottom or not self._check_collision(trimmed_char1, trimmed_char2, char2_start_pos, overlap_top, overlap_bottom): - return -overlap_pixels - - optimal_kerning = default_kerning - max_kerning_reduction - - return optimal_kerning - - def render_kerned_string(self, text_bytes: bytes, default_kerning: int = 1) -> np.ndarray: + # Calculate the actual position used in rendering (kerning + 1) + kerning = -overlap_pixels + actual_spacing = kerning + 1 + char2_start_pos = char1_width + actual_spacing + + if overlap_top <= overlap_bottom: + if self._check_collision( + trimmed_char1, + trimmed_char2, + char2_start_pos, + overlap_top, + overlap_bottom, + ): + continue + + diagonal_touches, orthogonal_touches = self._count_touches( + trimmed_char1, + trimmed_char2, + char2_start_pos, + overlap_top, + overlap_bottom, + ) + + # Reject if any orthogonal touches + if orthogonal_touches > 0: + continue + + if diagonal_touches == 1: + return kerning + elif diagonal_touches == 0: + best_kerning = kerning + + return best_kerning + + def render_kerned_string( + self, + text_bytes: bytes, + default_kerning: int = 1, + external_kerning_table: dict = None, + external_width_table: bytes = None, + ) -> np.ndarray: """ Render a string with optimal kerning between character pairs. - + Args: text_bytes: Bytes representing character indices (from table.to_bytes()) has_grid: Whether the font has grid lines char_width: Width of each character cell char_height: Height of each character cell default_kerning: Default spacing between characters - + Returns: 2D numpy array containing the rendered text with optimal kerning """ if len(text_bytes) == 0: return np.zeros((self.char_height, 0), dtype=np.uint8) - + self._load_image() - - # Get all character data and compute widths + + # Get all character data and determine widths chars = [] char_widths = [] for char_index in text_bytes: char_data = self.get_char(char_index) - actual_width = self.get_max_width(char_data) + + if external_width_table is not None: + # Use width from external table (file-based) + actual_width = external_width_table[char_index] + else: + # Compute width from PNG (autohint) + actual_width = self.get_max_width(char_data) + chars.append(char_data[:, :actual_width]) char_widths.append(actual_width) - + if len(chars) == 1: # Single character, no kerning needed return chars[0] - + # Calculate optimal kerning between each pair and total width kerning_values = [] total_width = char_widths[0] # First character width - + for i in range(len(text_bytes) - 1): char1_index = text_bytes[i] char2_index = text_bytes[i + 1] - kerning = self.compute_kerning(char1_index, char2_index, default_kerning) + 1 + + if ( + external_kerning_table + and (char1_index, char2_index) in external_kerning_table + ): + # Use external kerning table value (already includes the +1) + kerning = external_kerning_table[(char1_index, char2_index)] + 1 + elif external_kerning_table is not None: + # External kerning table provided but no entry for this pair - use default spacing + kerning = default_kerning + else: + # No external kerning table - use auto-generated kerning + kerning = ( + self.compute_kerning(char1_index, char2_index, default_kerning) + 1 + ) + kerning_values.append(kerning) total_width += kerning + char_widths[i + 1] - + # Create output array and place characters result = np.zeros((self.char_height, total_width), dtype=np.uint8) - + # Place first character current_pos = 0 - result[:, current_pos:current_pos + char_widths[0]] = chars[0] + result[:, current_pos : current_pos + char_widths[0]] = chars[0] current_pos += char_widths[0] - + # Place remaining characters with optimal kerning for i in range(1, len(chars)): kerning = kerning_values[i - 1] current_pos += kerning - - # Find vertical extent of current character for proper placement - char_rows_with_pixels = np.any(chars[i] > 0, axis=1) - char_top_row = np.argmax(char_rows_with_pixels) if np.any(char_rows_with_pixels) else 0 - char_bottom_row = len(char_rows_with_pixels) - 1 - np.argmax(char_rows_with_pixels[::-1]) if np.any(char_rows_with_pixels) else self.char_height-1 - - # Place character at its correct vertical position - result[char_top_row:char_bottom_row+1, current_pos:current_pos + char_widths[i]] = chars[i][char_top_row:char_bottom_row+1, :] + + # Place character, only overwriting with non-zero pixels + char_data = chars[i] + for row in range(char_data.shape[0]): + for col in range(char_data.shape[1]): + if char_data[row, col] > 0: # Only place non-zero pixels + result_col = current_pos + col + if result_col < result.shape[1]: + result[row, result_col] = char_data[row, col] + current_pos += char_widths[i] - + return result def render_string(self, text_bytes: bytes) -> np.ndarray: """ Render a string with fixed 1-pixel kerning between characters. - + Args: text_bytes: Bytes representing character indices (from table.to_bytes()) - + Returns: 2D numpy array containing the rendered text with 1-pixel spacing """ if len(text_bytes) == 0: return np.zeros((self.char_height, 0), dtype=np.uint8) - + self._load_image() - + # Get all character data and compute widths chars = [] char_widths = [] @@ -294,32 +492,290 @@ def render_string(self, text_bytes: bytes) -> np.ndarray: actual_width = self.get_max_width(char_data) chars.append(char_data[:, :actual_width]) char_widths.append(actual_width) - + if len(chars) == 1: # Single character, no kerning needed return chars[0] - + # Calculate total width with 1-pixel kerning between characters total_width = sum(char_widths) + (len(chars) - 1) # chars + gaps - + # Create output array and place characters result = np.zeros((self.char_height, total_width), dtype=np.uint8) - + # Place characters with 1-pixel spacing current_pos = 0 for i, char in enumerate(chars): # Find vertical extent of current character for proper placement char_rows_with_pixels = np.any(char > 0, axis=1) - char_top_row = np.argmax(char_rows_with_pixels) if np.any(char_rows_with_pixels) else 0 - char_bottom_row = len(char_rows_with_pixels) - 1 - np.argmax(char_rows_with_pixels[::-1]) if np.any(char_rows_with_pixels) else self.char_height-1 - + char_top_row = ( + np.argmax(char_rows_with_pixels) if np.any(char_rows_with_pixels) else 0 + ) + char_bottom_row = ( + len(char_rows_with_pixels) - 1 - np.argmax(char_rows_with_pixels[::-1]) + if np.any(char_rows_with_pixels) + else self.char_height - 1 + ) + # Place character at its correct vertical position - result[char_top_row:char_bottom_row+1, current_pos:current_pos + char_widths[i]] = char[char_top_row:char_bottom_row+1, :] + result[ + char_top_row : char_bottom_row + 1, + current_pos : current_pos + char_widths[i], + ] = char[char_top_row : char_bottom_row + 1, :] current_pos += char_widths[i] + 1 # Move to next position with 1-pixel gap - + return result - def find_kerning_pairs(self, table, test_pairs: List[str]) -> Dict[Tuple[int, int], int]: + def debug_kerned_string(self, text: str, table) -> None: + """Debug tool to display and analyze a kerned string with detailed information.""" + print(f"=== KERNING DEBUG: '{text}' ===") + + # Convert to bytes + text_bytes = table.to_bytes(text) + if not text_bytes: + print(f"Could not convert '{text}' to bytes") + return + + print(f"Text bytes: {[hex(b) for b in text_bytes]}") + print() + + # Analyze each character pair + pairs_info = [] + for i in range(len(text_bytes) - 1): + char1_index = text_bytes[i] + char2_index = text_bytes[i + 1] + char1_str = table.to_text(bytes([char1_index])) + char2_str = table.to_text(bytes([char2_index])) + + # Get character data + char1_data = self.get_char(char1_index) + char2_data = self.get_char(char2_index) + char1_width = self.get_max_width(char1_data) + char2_width = self.get_max_width(char2_data) + + # Compute kerning + kerning = self.compute_kerning(char1_index, char2_index, default_kerning=1) + actual_spacing = kerning + 1 + char2_start_pos = char1_width + actual_spacing + + # Count diagonal and orthogonal touches separately + diagonal_touches, orthogonal_touches = self._count_touches( + char1_data[:, :char1_width], + char2_data[:, :char2_width], + char2_start_pos, + 0, + 15, + ) + + # Check for direct collisions + has_collision = self._check_collision( + char1_data[:, :char1_width], + char2_data[:, :char2_width], + char2_start_pos, + 0, + 15, + ) + + pairs_info.append( + { + "pair": f"{char1_str}{char2_str}", + "chars": (char1_index, char2_index), + "widths": (char1_width, char2_width), + "kerning": kerning, + "actual_spacing": actual_spacing, + "char2_start_pos": char2_start_pos, + "diagonal_touches": diagonal_touches, + "orthogonal_touches": orthogonal_touches, + "has_collision": has_collision, + } + ) + + print( + f"Pair {i + 1}: '{char1_str}'{char2_str}' ({char1_index:02x},{char2_index:02x})" + ) + print(f" Widths: char1={char1_width}, char2={char2_width}") + print(f" Kerning: {kerning} (actual spacing: {actual_spacing})") + print(f" Char2 starts at position: {char2_start_pos}") + print(f" Diagonal touches: {diagonal_touches}") + print(f" Orthogonal touches: {orthogonal_touches}") + print(f" Direct collision: {has_collision}") + print() + + # Render the string + kerned_render = self.render_kerned_string(text_bytes) + simple_render = self.render_string(text_bytes) + + print("KERNED RENDER:") + self._display_render_with_boundaries(kerned_render, pairs_info) + + print("\nSIMPLE RENDER (1px spacing):") + for i, row in enumerate(simple_render): + row_str = "".join("█" if pixel == 1 else " " for pixel in row) + print(f"{i:2d}: {row_str}") + + print( + f"\nWidth comparison: Kerned={kerned_render.shape[1]}, Simple={simple_render.shape[1]}" + ) + print(f"Space saved: {simple_render.shape[1] - kerned_render.shape[1]} pixels") + + def _display_render_with_boundaries(self, render, pairs_info): + """Display render with character boundaries marked.""" + # Calculate character boundaries + boundaries = [] + current_pos = 0 + + # First character + if pairs_info: + char1_width = pairs_info[0]["widths"][0] + boundaries.append(current_pos + char1_width - 1) # End of char1 + current_pos += char1_width + + # Remaining characters + for info in pairs_info: + current_pos += info["actual_spacing"] + char2_width = info["widths"][1] + boundaries.append(current_pos + char2_width - 1) # End of char2 + current_pos += char2_width + + # Create column numbers header + col_nums = "".join(str(i % 10) for i in range(render.shape[1])) + print(f" {col_nums}") + + # Display each row with boundary markers + for i, row in enumerate(render): + row_str = "".join("█" if pixel == 1 else " " for pixel in row) + + # Add boundary markers + marked_row = list(row_str) + for boundary in boundaries: + if boundary < len(marked_row): + if marked_row[boundary] == "█": + marked_row[boundary] = "╬" # Character pixel at boundary + else: + marked_row[boundary] = "|" # Empty space at boundary + + print(f"{i:2d}: {''.join(marked_row)}") + + def debug_diagonal_touches(self, pair: str, table, test_kerning: int) -> None: + """Debug tool to visualize diagonal touches for a character pair at a specific kerning.""" + print(f"=== DIAGONAL TOUCHES DEBUG: '{pair}' at kerning {test_kerning} ===") + + # Convert to bytes + chars = table.to_bytes(pair) + if len(chars) != 2: + print(f"Could not convert '{pair}' to character pair") + return + + char1_data = self.get_char(chars[0]) + char2_data = self.get_char(chars[1]) + char1_width = self.get_max_width(char1_data) + char2_width = self.get_max_width(char2_data) + + # Calculate positioning + actual_spacing = test_kerning + 1 + char2_start_pos = char1_width + actual_spacing + + print(f"char1_width={char1_width}, char2_width={char2_width}") + print(f"actual_spacing={actual_spacing}, char2_start_pos={char2_start_pos}") + print() + + # Create combined render and track ownership + total_width = max(char1_width, char2_start_pos + char2_width) + combined = np.zeros((16, total_width), dtype=np.uint8) + ownership = np.zeros((16, total_width), dtype=np.uint8) # 1=char1, 2=char2 + + # Place char1 first + for row in range(char1_data.shape[0]): + for col in range(char1_width): + if char1_data[row, col] > 0: + combined[row, col] = char1_data[row, col] + ownership[row, col] = 1 + + # Place char2, only non-zero pixels + for row in range(char2_data.shape[0]): + for col in range(char2_width): + if char2_data[row, col] > 0: + result_col = char2_start_pos + col + if 0 <= result_col < total_width: + combined[row, result_col] = char2_data[row, col] + ownership[row, result_col] = 2 + + # Find diagonal touches and mark them + touch_pairs = set() + touch_pixels = set() # All pixels involved in touches + + for row in range(16): + for col in range(total_width): + if combined[row, col] == 1: + pixel_owner = ownership[row, col] + + # Check all 4 diagonal directions + for dr, dc in [(1, 1), (1, -1), (-1, 1), (-1, -1)]: + new_row, new_col = row + dr, col + dc + if ( + 0 <= new_row < 16 + and 0 <= new_col < total_width + and combined[new_row, new_col] == 1 + ): + neighbor_owner = ownership[new_row, new_col] + + # Only count touches between different characters + if ( + pixel_owner != neighbor_owner + and pixel_owner > 0 + and neighbor_owner > 0 + ): + # Create a unique key for this touch pair + touch_key = tuple( + sorted([(row, col), (new_row, new_col)]) + ) + if touch_key not in touch_pairs: + touch_pairs.add(touch_key) + touch_pixels.add((row, col)) + touch_pixels.add((new_row, new_col)) + direction_name = { + (1, 1): "↘", + (1, -1): "↙", + (-1, 1): "↗", + (-1, -1): "↖", + }[dr, dc] + char_type1 = ( + "char1" if pixel_owner == 1 else "char2" + ) + char_type2 = ( + "char2" if neighbor_owner == 2 else "char1" + ) + print( + f"Touch: {char_type1}({row},{col}) {direction_name} {char_type2}({new_row},{new_col})" + ) + + print(f"\\nTotal diagonal touches found: {len(touch_pairs)}") + print() + + # Create visualization + print("Visualization (* = touch pixel, █ = regular pixel, · = empty):") + col_nums = "".join(str(i % 10) for i in range(total_width)) + print(f" {col_nums}") + + for row in range(16): + row_str = "" + for col in range(total_width): + if (row, col) in touch_pixels: + row_str += "*" + elif combined[row, col] == 1: + row_str += "█" + else: + row_str += "·" + print(f"{row:2d}: {row_str}") + + print() + print( + f"Character boundary: char1 ends at col {char1_width - 1}, char2 starts at col {char2_start_pos}" + ) + + def find_kerning_pairs( + self, table, test_pairs: List[str] + ) -> Dict[Tuple[int, int], int]: """Find character pairs that benefit from kerning.""" kerning_pairs = {} @@ -330,20 +786,24 @@ def find_kerning_pairs(self, table, test_pairs: List[str]) -> Dict[Tuple[int, in continue try: - optimal_kerning = self.compute_kerning(chars[0], chars[1], default_kerning=1) - if optimal_kerning < -1: - optimal_kerning = 0 + optimal_kerning = self.compute_kerning( + chars[0], chars[1], default_kerning=1 + ) # Skip useless entries: # - Same as default (no benefit) # - Invalid kerning values - if optimal_kerning != 1 and optimal_kerning < 0: # Different from default and valid + if ( + optimal_kerning != 1 and optimal_kerning < 0 + ): # Different from default and valid kerning_pairs[(chars[0], chars[1])] = optimal_kerning char1_str = table.to_text(bytes([chars[0]])) char2_str = table.to_text(bytes([chars[1]])) - print(f" {pair} '{chars[0]}{chars[1]}' ({chars[0]:02x},{chars[1]:02x}): kerning = {optimal_kerning}") + print( + f" {pair} '{chars[0]}{chars[1]}' ({chars[0]:02x},{chars[1]:02x}): kerning = {optimal_kerning}" + ) except Exception as e: print(f" Warning: Failed to compute kerning for '{pair}': {e}") continue print(f"Found {len(kerning_pairs)} pairs that benefit from kerning") - return kerning_pairs \ No newline at end of file + return kerning_pairs diff --git a/utils/smallvwf.py b/utils/smallvwf.py index 36c62b0..05014e5 100644 --- a/utils/smallvwf.py +++ b/utils/smallvwf.py @@ -12,11 +12,11 @@ def text_to_char(text): data = [] for char in text: - if 'A' <= char <= 'Z': - data.append(ord(char) - ord('A') + 0x42) - elif 'a' <= char <= 'z': - data.append(ord(char) - ord('a') + 0x42 + ord('Z') - ord('A') + 1) - elif char == ' ': + if "A" <= char <= "Z": + data.append(ord(char) - ord("A") + 0x42) + elif "a" <= char <= "z": + data.append(ord(char) - ord("a") + 0x42 + ord("Z") - ord("A") + 1) + elif char == " ": data.append(0xFF) return data @@ -35,7 +35,7 @@ def build_text_image(font_file, text_data): width = 2 else: width = get_max_width(current_char) - culled_char = current_char[0:8, 0:width + 1] + culled_char = current_char[0:8, 0 : width + 1] # print(culled_char) if buffer is not None: buffer = np.concatenate((buffer, culled_char), 1) @@ -48,37 +48,37 @@ def build_text_image(font_file, text_data): classes = [ - 'Chevalier noir ', - 'Chevalier dragon ', - 'Invokeur ', - 'Sage ', - 'Menestrel ', - 'Sorcier Blanc ', - 'Moine ', - 'Sorcier Noir ', - 'Sorcier Blanc ', - 'Paladin ', - 'Ingenieur ', - 'Invoker ', - 'Ninja ', - 'Selenite ' + "Chevalier noir ", + "Chevalier dragon ", + "Invokeur ", + "Sage ", + "Menestrel ", + "Sorcier Blanc ", + "Moine ", + "Sorcier Noir ", + "Sorcier Blanc ", + "Paladin ", + "Ingenieur ", + "Invoker ", + "Ninja ", + "Selenite ", ] character_name = [ - 'Cecil ', - 'Cain ', - 'Rydia ', - 'Tella ', - 'Gilbert', - 'Rosa ', - 'Yang ', - 'Palom ', - 'Porom ', - 'Cid ', - 'Edge ', - 'FuSoYa', - 'Golbez', - 'Anna ' + "Cecil ", + "Cain ", + "Rydia ", + "Tella ", + "Gilbert", + "Rosa ", + "Yang ", + "Palom ", + "Porom ", + "Cid ", + "Edge ", + "FuSoYa", + "Golbez", + "Anna ", ] menu_items = [ @@ -91,20 +91,20 @@ def build_text_image(font_file, text_data): # 'Options', # 'Sauver', # 'Petit Meteore', - 'Chevalier noir', - 'Chevalier dragon', - 'Invokeur', - 'Sage', - 'Menestrel', - 'Sorcier Blanc', - 'Moine', - 'Sorcier Noir', - 'Sorcier Blanc', - 'Paladin', - 'Ingenieur', - 'Invoker', - 'Ninja', - 'Selenite' + "Chevalier noir", + "Chevalier dragon", + "Invokeur", + "Sage", + "Menestrel", + "Sorcier Blanc", + "Moine", + "Sorcier Noir", + "Sorcier Blanc", + "Paladin", + "Ingenieur", + "Invoker", + "Ninja", + "Selenite", ] @@ -120,6 +120,7 @@ def build_text_image(font_file, text_data): # know the tile_id and tile_count ? # ring buffer ? + class VwfAsset: def __init__(self, font_file: str, table: Table) -> None: self.font = np.array(Image.open(font_file)) @@ -137,7 +138,7 @@ def get_char(self, char: int) -> np.ndarray: else: width = get_max_width(current_char) - return current_char[0:8, 0:width + 1] + return current_char[0:8, 0 : width + 1] def render_string(self, string: str) -> np.ndarray | None: buffer: np.ndarray | None = None @@ -168,46 +169,54 @@ def serialize(self) -> bytearray: for string, rendered_string in self.rendered_strings.items(): serialized_string = write_as_2bpp(rendered_string) - pointers.append((len(data) + data_origin, len(serialized_string), len(serialized_string) // 16)) + pointers.append( + ( + len(data) + data_origin, + len(serialized_string), + len(serialized_string) // 16, + ) + ) data += serialized_string pointer_data = bytearray() for pointer in pointers: - pointer_data += struct.pack(">HBB", pointer[0] & 0xffff, pointer[1], pointer[2]) - + pointer_data += struct.pack( + ">HBB", pointer[0] & 0xFFFF, pointer[1], pointer[2] + ) return pointer_data + data - - - - def generate_8x8_vwf_asset(string_list, prefix, table_start, max_tile_length=None): k = 0 current_id = table_start - with open('assets/%s.bin' % prefix, 'wb') as output: - with open('assets/%s.len' % prefix, 'wb') as length_table: - with open('text/%s.tbl' % prefix, 'wt', encoding='utf-8') as table: + with open("assets/%s.bin" % prefix, "wb") as output: + with open("assets/%s.len" % prefix, "wb") as length_table: + with open("text/%s.tbl" % prefix, "wt", encoding="utf-8") as table: if max_tile_length: - line_length = (max_tile_length * 2 * 8) + line_length = max_tile_length * 2 * 8 for string in string_list: if max_tile_length: output.seek(k * line_length) - data = build_text_image('fonts/8x8vwf2p.png', string.strip()) + data = build_text_image("fonts/8x8vwf.png", string.strip()) data_2bpp = write_as_2bpp(data) output.write(data_2bpp) - length_table.write(struct.pack('[new]\n', output) - output = re.sub(r'\[new\]\n\[end\]', '[end]', output) - return output - - -if __name__ == '__main__': - print(vwf_text_format(text)) \ No newline at end of file