Pointer
Nếu đã nắm kỹ những gì tôi nói bên trên thì tại thời điểm này, bạn đã có thể dịch một game sang thứ tiếng mà bạn muốn. Nhưng như vậy chưa phải là đủ. Vì sao?
Vì một lý do rất đơn giản: như tôi có đề cập ở phần trước, các câu thoại trong Rom thường được sắp xếp nối tiếp nhau tạo thành một khối hội thoại. Trong đó câu 1 ngăn cách với câu 2, câu 3, câu 4,… bằng control code chỉ định kết thúc câu. Và thông thường thì khi dịch một câu từ ngôn ngữ nguồn sang ngôn ngữ đích thì câu được dịch dài hơn câu gốc, do đó dẫn đến hiện tượng không đủ chỗ nếu muốn dịch hết và dịch đầy đủ và hiện tượng các câu nằm chồng lên nhau như hình minh họa dưới đây
Phần màu hồng là 3 câu trong ngôn ngữ nguồn và phần màu đen là 3 câu đã được dịch ra. Một ví dụ khác, nếu mỗi một chữ cái là một Hex code và block hội thoại của chúng ta gồm 2 câu: Hello<end>Goodbye<end>
(<end> tượng trưng cho Hex code chỉ kết thúc câu). Trong trường hợp này thì block của chúng ta có 14 Hex code (14 bytes) bao gồm cả 2 control code. Nếu dịch block này sang tiếng Việt thì
Như vậy thì chưa dịch hết câu thứ 2 trong block mà chúng ta đã sử dụng hết 14 bytes. Trường hợp nếu chỉ dịch câu đầu tiên trong block thì
Rõ ràng bạn thấy câu 1 (được dịch) lấn sang câu 2 (chưa dịch). Vậy phải giải quyết trường hợp này như thế nào?
Có nhiều cách để giải quyết:
+ Dùng kiến thức Asm để viết lại toàn bộ cấu trúc lời thoại, sắp xếp lại các câu thoại.
+ Dùng kiến thức Asm để mở rộng Rom, tăng thêm chỗ trống cho các câu thoại.
+ Dùng Pointer.
Trong các cách trên thì sử dụng Pointer không đòi hỏi phải có kiến thức về Asm và là vũ khí duy nhất của bạn trong giai đoạn này. Phần này tôi sẽ giải thích về Pointer và cách hoạt dụng của nó. Đây là phần
quan trọng nhất trong toàn bộ bài viết này, nếu không nắm và ứng dụng được nó thì rất nhiều khả năng Project dịch thuật của bạn bị phá sản.
Vậy pointer là gì?
Như mọi thành phần khác trong Rom, Pointer cũng chỉ là các Hex code (có thể là 2 bytes, 3 bytes, 4 bytes,…). Và đúng như tên gọi của nó, các Hex code này làm nhiệm vụ chỉ chỗ (địa chỉ) cho game đọc dữ liệu (trong trường hợp này là text) cần thiết. Chẳng hạn, trong Rom Super Mario Bros. có sẵn đoạn text “Game Over” và đoạn này được hiển thị ra màn hình khi người chơi “hết mạng”.
Nguyên tắc hoạt động như sau: game kiểm tra xem người chơi còn bao nhiêu “mạng”, nếu số “mạng” bằng 0 thì nó sẽ đọc một Pointer và Pointer này chỉ đến vị trí của đoạn text “Game Over”. Nhưng Pointer không chỉ đến toàn vị trí của toàn dữ liệu (dòng text “Game Over”) mà nó chỉ tới byte đầu tiên trong khối dữ liệu đó (cụ thể ở đây là chữ G). CPU sẽ đọc từ byte đầu tiên được Pointer dẫn đường này cho tới khi gặp control code báo kết thúc.
Mọi thành phần trong Rom được xác định bằng
hai thành phần cơ bản là giá trị Hex của nó và địa chỉ (offset) của nó.
Để dễ hiểu hơn, bạn hãy làm theo hướng dẫn như dưới đây.
Đầu tiên hãy load Rom FE3 gốc (chưa thay đổi font chữ) và chơi đoạn mở đầu, xác nhận lời thoại đầu tiên trong game là câu sau
Đoạn, load Rom bằng Winhed và file Table, bạn dễ dàng tìm được vị trí bắt đầu của đoạn hội thoại này trong Rom là $71A3C (đối với Rom có 200 bytes header). Thử thay đổi vài Hex code để xác nhận xem địa chỉ bạn tìm được đã chính xác chưa rồi backup lại Rom. Bây giờ nhảy tới địa chỉ $71416, tại đây bạn sẽ thấy các Hex code: 2E-98-8E-4D-99-8E-41-9B-8E…
Thử thay đổi 3 bytes đầu tiên là 2E-98-8E thành 4D-99-8E, save Rom và kiểm tra bằng giả lập.
Kỳ lạ thay! Đoạn hội thoại mở đầu đã thay đổi hoàn toàn trong khi bạn chỉ edit mỗi 3 bytes ở một địa chỉ khác hoàn toàn không liên quan đến text hội thoại. Giờ hãy thay đổi 3 bytes vừa rồi thành 41-9B-8E xem sao.
Đoạn hội thoại mở đầu lại thay đổi!
Điều này nghĩa là sao? Tôi sẽ giải thích qua, hãy đọc kỹ phần dưới đây.
Bạn vừa edit 3 bytes đầu tiên tại địa chỉ $71A3. Địa chỉ này tuy không phải là địa chỉ chứa text nhưng lại là nơi chứa các Pointer chỉ đến các đoạn hội thoại nằm ở chỗ khác trong Rom. Và 3 bytes bạn vừa edit chính là giá tri của Pointer chỉ đến đoạn hội thoại mở đầu game. Vì vậy, khi edit 3 bytes này tức là bạn đã edit giá trị của Pointer và nó sẽ chỉ đến đoạn hội thoại khác, tùy vào giá trị mà bạn edit. Nói cách khác,
giá trị của Pointer chính là địa chỉ của dữ liệu (text) mà nó chỉ đến. Game Snes sử dụng các loại Pointer sau:
+ Pointer 16 bit hay còn gọi là Pointer 2 bytes. Chính vì có độ dài 2 bytes nên nó có thể chỉ tới bất kỳ vị trí nào trong phạm vi từ $00~$FFFF. FF4 trên Snes là game sử dụng Pointer 2 bytes.
+ Pointer 32 bit hay còn gọi là Pointer 3 bytes. hính vì có độ dài 2 bytes nên nó có thể chỉ tới bất kỳ vị trí nào trong phạm vi từ $00~$FFFFFF. Vì dung lượng của game Snes thường được giới hạn trong phạm vi 4Mb nên Pointer 3 bytes có thể chỉ tới bất cứ vị trí nào trong Rom. FE3 là game sử dụng Pointer 3 bytes.
Lưu ý rằng các hệ máy khác nhau thì dùng Pointer có kích thước khác nhau.
Lợi ích của Pointer:
Như đã nói trên, Pointer là vũ khí lợi hại nhất của bạn trong giai đoạn này để giải quyết vấn đề thiếu chỗ trống trong Rom. Bởi vì trong Rom luôn tồn tại những vị trống, tức là vị trí mà tại đó không chứa bất kỳ dữ liệu nào của Rom (thường là khu vực với Hex $00 hoặc $FF) nên bạn có thể chuyển chỗ những câu thoại dài trong block hội thoại ra những khu vực trống này và edit lại Pointer để nó chỉ tới vị trí hội thoại mới.
Trong hình trên, màu đỏ là vị trí các câu hội thoại ban đầu trong block, màu đen là sau khi dời một số câu đi chỗ khác. Mũi tên là các Pointer.
Do vậy dễ dàng thấy rằng tuy bản thân việc edit giá trị của Pointer không làm tăng thêm chỗ trống cũng như không làm giảm đi kích thước của văn bản nhưng nó cho phép ta sắp xếp các câu thoại vào từng chỗ trong Rom hiệu quả hơn. Những người dịch game bằng cách edit text trực tiếp mà không dùng đến Pointer thường lâm vào tình cảnh không đủ chỗ trống để dịch câu đầy đủ nên phải sử dụng khá nhiều từ viết tắt, lược bỏ đi nhiều từ và do vậy chất lượng của bản dịch cũng không được nguyên vẹn trong khi đó trong Rom vẫn còn nhiều chỗ trống khác.
Nói cách khác,
Pointer giúp bạn khai thác hiệu quả không gian trống trong Rom nếu sử dụng đúng cách và là vũ khí quan trọng bậc nhất trong việc hách Rom.