Trang phân tích mọi khía cạnh kỹ thuật của Final Fantasy VIII (FF8) do Square Soft phát triển cho máy chơi game Sony PlayStation (PSX), được phát hành ra thị trường vào năm 1999. Phần này được biên soạn lại từ những ghi chú cá nhân trong quá trình debug bản PSX sau khi hoàn thiện bản dịch tiếng Việt cho phiên bản FF8 PC vào năm 2014. STONE BOAT - FINAL FANTASY VIII (google.com) Những phân tích trong trang này dựa trên đối tượng là Rom bản tiếng Nhật. Bản Âu-Mỹ có thể khác đôi chút, nhưng những nét chính thì vẫn giống vậy. 1. Các kiểu thoại Phần thoại (text) xuất hiện trong các phiên bản Final Fantasy, không riêng gì FF8, đều nằm ở ba tình huống với cách gọi tên như bên dưới. Battle: những đoạn text xuất hiện trong trận đấu, chẳng hạn như khi Quistis nhắc Squall nhấn L1 để đánh nổ bằng Gunblade ở đầu Disc 1, trong trận đánh đầu tiên. World Map: những đoạn text xuất hiện khi nhân vật lang thang trên World Map, chẳng hạn như khi gặp event ném viên đá trên mặt hồ. Menu: phần text xuất hiện khi truy cập Menu bằng cách nhấn nút tam giác (mặc định bản Âu-Mỹ là nút tròn), chẳng hạn như text giải thích Item, tên nhân vật,.... Field: là các địa điểm mà khi vào đó, góc Camera sẽ cố định và không xảy ra những trận đánh ngẫu nhiên. Balamb Garden, thành phố Timber, thành phố Galbadia, khu di tích Centra,... đều là các Field. FF8 có số lượng lời thoại nhiều kinh khủng, trong đó phần thoại xuất hiện trong các Field chiếm phần lớn. Phần text ở Field là đối tượng được quan tâm nhất trong các bản dịch ngôn ngữ khác. Khi mở Rom FF8 bằng các phần mềm chuyên đọc CD-Rom như CDMage thì sẽ thấy cả 4 disc của FF8 đều có cấu trúc giống nhau, gồm có 3 file như dưới đây. FF8DISCZZZ.IMG SLPS_018.8ZZZ SYSTEM.CNF SYSTEM.CNF là file chứa các tham số liên quan tới lệnh khởi động máy PSX, còn SLPS_018.8ZZZ (ZZZ là 0 với Disc1, là 1 với Disc2,....) là file thực thi (exe) của máy PSX, chứa mã máy để thực thi game. Các lệnh chính của game đều được chứa trong file này. File FF8DISCZZZ.IMG (ZZZ là 1 với Disc1, là 2 với Disc2,...) là nơi chứa dữ liệu hình ảnh, các loại texture, dữ liệu video/âm thanh, các loại pointer, dữ liệu hội thoại và một phần lệnh thi hành. Dữ liệu text trong Menu và World Map được DMA từ CD-ROM (từ file FF8DISCZZZ.IMG) vào Ram ngay sau khi khởi động máy, nên máy có thể truy cập vào những đoạn text này vào bất cứ lúc nào khi người chơi nhấn nút bật Menu. Còn với dữ liệu text của Field và Battle chỉ được DMA vào Ram khi vào trận đánh hoặc vào Field tương ứng. Dữ liệu thoại của Menu, World Map, Battle đều ở dạng không nén, còn dữ liệu thoại của Field thì được nén theo kiểu lzss. Mỗi khối dữ liệu thoại trong Field bao gồm: góc camera trong field đó, các event điều khiển nhân vật qua lại/cử chỉ khi nói chuyện, đường đi trong field, pointer dẫn tới dữ liệu thoại, dữ liệu thoại, font chữ Kanji đặc biệt (không được dùng tới trong bản Âu-Mỹ). Mỗi khối thoại trong Field được đặt tên theo từng Field + vị trí trong Field. Những câu thoại được kích hoạt trong cùng một khu vực được xếp chung trong một khối dữ liệu. Chẳng hạn, lời thoại ở các khu vực trên tầng 2 của Balamb Garden, gồm phòng học, hành lang,... được xếp vào các khối dữ liệu có tên: bg2f_1, bg2f_11, bg2f_21, bg2f_4,... Trong đó "bg" là viết tắt của Balamb Garden. Lưu ý là những từ viết tắt này chủ yếu là của tiếng Nhật, ít khi là viết tắt của từ tiếng Anh. Chẳng hạn, các khối thoại xảy ra trong phòng y tế của Balamb Garden gồm có: bghoke_1, bghoke_2, bghoke_3 trong đó "hoke" là viết tắt của "hokenshitsu" (保健室 - phòng y tế) hay những khối thoại xảy ra ở khu vực nhà dân ở Timber gồm có: timin1, timin21, timin22.... Trong đó "ti" là viết tắt của "Timber", còn "min" là viết tắt của "minke" trong tiếng Nhật (民家-nhà dân). Trong một số ít trường hợp thì tên của khối dữ liệu được đặt theo tiếng Anh, chẳng hạn như tipub1 là những đoạn thoại xảy ra trong quán rượu ở Timber. Có thể dò tìm vị trí của từng khối dữ liệu bằng cách dùng Binary editor (Hex editor) để tìm những từ khóa (định dạng Ascii) như trên đối với file Ram dump, hoặc với FF8DISCZZZ.IMG. Tuy nhiên, đối với file IMG thì khối dữ liệu ở dạng đã nén (lzss) nên đôi khi sẽ không tìm thấy từ khóa cần thiết. Còn với file Ram dump, do ở dạng không nén nên kết quả dò tìm luôn trúng.
2. Font chữ Mọi hình ảnh 2D trong game PSX đều ở dạng tim, kể cả font chữ. Tim là một định dạng hình ảnh của Sony, được dùng cho máy PSX, có cấu trúc như được đề cập ở phần bên dưới. Và dĩ nhiên, font chữ trong game cũng ở định dạng tim, độ sâu màu 4bpp. Tất cả các khối thoại trong game, dù là Battle, Menu, World Map hay Field cũng đều dùng chung một bộ font dạng tim có kích cỡ mỗi ký tự là 12 x 12 pixel. Tuy nhiên, một phần cục bộ trong Menu (như phần tên của G.F.) được trình bày bằng font 8 x 8 pixel. Cách chắc chắn nhất để tìm được font chữ trong game là dump Vram. Dùng debugger chơi tới đoạn có thoại, rồi dump Vram. Sau đó dùng công cụ Vram Viewer để xem vị trí của bộ font. Công cụ Vram Viwer cho ta biết địa chỉ của bộ font trong Vram của máy PSX bắt đầu tại $80780. Từ đây có hai cách để xác định được vị trí của nó trong CD-Rom. Thứ nhất là reset về đầu game rồi dùng chức năng trace log của debugger để tìm xem bộ font này được DMA vào Vram từ địa chỉ nào. Cách thứ hai, là cách đơn giản hơn: dùng Binary editor để xem dữ liệu ở địa chỉ $80780 trong file Vram, copy những dữ liệu này rồi tìm kiếm trong CD-Rom (file FF8DISCZZZ.IMG) . Dù là cách nào đi nữa thì kết quả cũng đều giống nhau. Khối dữ liệu font (tim) bắt đầu tại $BDE4 trong các file FF8DISCZZZ.IMG, và địa chỉ này là cố định cho cả 4 disc. Tuy nhiên, khối dữ liệu này không đơn thuần là file tim, nên các phần mềm dò định dạng tim như timviwer hay tim2view sẽ không dò được bộ font này trong Rom. Phần dữ liệu tim này chỉ là một thành phần của file "font.tdw" bắt đầu ở địa chỉ $BD80. Cấu trúc của file này như sau. 00000008: pointer đến dữ liệu độ rộng của ký tự 000001C4: pointer đến dữ liệu tim (font chữ) FF8 dùng kiểu font chữ có độ rộng biến thiên (proportional font/variable width font), rất thuận tiện cho việc dịch thuật sang các ngôn ngữ dùng mẫu tự La Tinh. Chỉ cần điều chỉnh các giá trị tại table này là ta có thể tùy chỉnh độ rộng của từng ký tự theo ý muốn. Phần dữ liệu thật (hình ảnh/tim) của font chữ bắt đầu ở $01C4, tương đương với $B800 + $01C4 = $B9C4 trong file FF8DISCZZZ.IMG. Cấu trúc của file tim gồm các thành phần được sắp xếp theo thứ tự như bên dưới. Header #1: gồm các pointer dẫn tới dữ liệu CLUT (Color Look UP Table, pallet màu của máy PSX) Dữ liệu CLUT Header #2: gồm các pointer dẫn tới dữ liệu tim Dữ liệu tim Cụ thể, ở header #1: 00000010: chèn 4 byte, có giá trị 0x10: đây là số ID cố định đánh dấu mở đầu file tim 4 byte cho biết định dạng của tim, có cấu trúc bit: "xxxx-xxxx xxxx-xxxx xxxx-xxxx xxxx-abbb" Trong đó các bit x là zero, bit a cho biết file tim đó có dùng CLUT hay không. Bit a set là file tim có CLUT, bit a reset là không có CLUT. Các bit bbb có ý nghĩa: 000: tim có độ sâu màu 4bpp (16 màu) 001: 8 bpp (64 màu) 010: 16 bpp (256 màu) 111: định dạng hỗn hợp Như vậy, nếu cụm bit này có giá trị 0x08 thì có nghĩa là file tim này có dùng CLUT, định dạng 8 bpp, nếu giá trị là 0x09 thì là file tim dạng 16 bpp và có dùng CLUT,... 4 byte thể hiện kích thước của khối CLUT + 0x0C byte (vì phần header chiếm mất 12 byte) 2 byte báo tọa độ X của khối CLUT trong Vram 2 byte báo tọa độ Y của khối CLUT trong Vram 2 byte báo số màu trong mỗi CLUT. Giá trị này luôn cố định là 16 (0x10) 2 byte báo số lượng CLUT có trong file tim Ta cũng có thể tìm được tọa độ X-Y của khối CLUT bằng công cụ Vram Viwer. Liền sau phần header #1 là phần dữ liệu CLUT. Nếu thay đổi những giá trị ở đây thì màu sắc của chữ trong game cũng thay đổi. Ngay sau khi kết thúc phần dữ liệu CLUT là tới phần header #2, gồm những thông tin: 4 byte kích thước của khối tim + 0x0C byte 2 byte tọa độ X của khối tim trong Vram 2 byte tọa độ Y của khối tim trong Vram 2 byte độ rộng của hình ảnh tim (phải nhân với 4 để ra kích thước thật) 2 byte chiều cao của hình ảnh tim Phần khai báo tọa độ X-Y ở đây chính là giá trị tọa độ X-Y mà ta có thể xác nhận bằng Vram Viewer. Và ngay sau phần header #2 là phần dữ liệu thật của tim. Bằng cách dùng Binary editor, ta có thể cắt riêng những thông tin trên để tạo thành một file tim riêng biệt, và rồi sau đó dùng những công cụ như timviewer để chuyển đổi font từ định dạng tim sang dạng hình ảnh bmp/png, chỉnh sửa thành mẫu tự tiếng Việt, rồi chuyển lại thành dạng tim, chèn vào Rom.
3. Độ rộng font chữ Thường thì các game tiếng Nhật không dùng tới chức năng chỉnh độ rộng cho từng ký tự, mà tất cả ký tự đều có độ rộng cố định. Kiểu font này được gọi là "monospace font" hoặc "fixed-width font". Còn với các văn bản dùng mẫu tự La Tinh thì người ta thường dùng kiểu font có độ rộng biến thiên theo từng ký tự, được gọi là "proportional font" hoặc "variable width font". Với kiểu thứ hai thì độ rộng của chữ "i" hẹp hơn của chữ "a", tạo nên tính thẩm mỹ của văn bản. Thật khó chịu khi gặp văn bản dùng ký tự La Tinh như tiếng Việt, tiếng Anh mà lại dùng kiểu fixed-width. Đối với giới dịch game thì việc chuyển từ kiểu fixed-width của tiếng Nhật sang kiểu variable width là một tiêu chí lớn. Việc này tuy không khó nhưng cũng đòi hỏi một nền tảng kiến thức vững chắc về phần cứng, phần mềm cũng như cách thức hoạt động của bộ font mới có thể làm được. So sánh tính thẩm mỹ giữa kiểu variable width và kiểu fixed width Nhưng may thay, FF8 không dùng font kiểu fixed-width mà dùng kiểu font có độ rộng biến thiên. Dữ liệu độ rộng của từng ký tự được tích hợp luôn trong file tim thể hiện font. Phần dưới đây phân tích cách CPU xử lý dữ liệu độ rộng của từng ký tự ở màn hình đầu tiên của game, ngay sau logo của Square Soft. Đầu tiên, khối dữ liệu gồm cả độ rộng font chữ và dữ liệu tim của font chữ được DMA từ CD-ROM vào địa chỉ Ram $801B0000, sau đó khối dữ liệu tại địa chỉ này được copy vào địa chỉ Ram $800821F8 qua routine nằm trong file exe (SLPS_018.8ZZZ). org $8002C4C8 LW v0, 0x0000(a2) LW v1, 0x0004(a2) LW a0, 0x0008(a2) LW a1, 0x000C(a2) SW v0, 0x0000(a3) SW v1, 0x0004(a3) SW a0, 0x0008(a3) SW a1, 0x000C(a3) ADDIU a2, a2, 0x0010 BNE a2, t0, 0x8002C4C8 ADDIU a3, a3, 0x0010 Trong đó Register $a2 chứa địa chỉ nguồn ($801B0000) còn Register $a3 chứa địa chỉ đích ($800821F8), còn t0 là điểm kết thúc của chuỗi dữ liệu. Toàn bộ quá trình đọc text và xử lý độ rộng font chữ được trình bày qua routine bên dưới. org $801F1804 LBU s0, 0x00(s4) //đọc text vào s0 ADDIU v0, r0, 0x02 //v0=2 BNE v0, s0, 801F1820 ADDIU s4, s4, 0x01 //địa chỉ text + 1 byte LW s3, 0x18(sp) J 0x801F1804 //xử lý code xuống dòng khi giá trị text = 0x02 ADDIU s5, s5, 0x0D //s5: tổng chiều cao (pixel) của ký tự 801F1820: ADDIU v0, r0, 0x05 BNE s0, v0, 801F18AC SLTI v0, s0, 0x19 //set v0 nếu giá trị text (s0) nhỏ hơn 0x19 LUI v1, 0xE100 //phần này trở đi biến hình ảnh chữ cái thành con trỏ (giá trị text = 0x05) ORI v1, v1, 0x041F org $801F18AC BNE v0, r0, 801F1920 SLTI v0, s3, 0x0181 //set v0 nếu tổng độ rộng ký tự trong chuỗi nhỏ hơn 0x0181 pixel BEQ v0, r0, 801F1920 //rẽ nhánh tới $801F1920 nếu tổng độ rộng không nhỏ hơn 0x0181 pixel SLTI v0, s0, 0x20 //set v0 nếu giá trị text nhỏ hơn 0x20 (control code) BNE v0, r0, 801F18CC SLL v0, s0, 0x03 //v0 = s0 <<3 J 0x801F81E4 ADDIU s0, s0, 0xFFE0 //s0 = s0 -20 do ký tự Kana có giá trị từ 0x20 trở lên SUBU v0, v0, s0 //v0 = s0<<3 - s0 SLL s0, v0, 0x05 //s0 = v0<<5 LBU v0, 0x00(s4) //đọc byte tiếp theo của control code ADDIU s4, s4, 0x01 ADDU s0, s0, v0 ADDIU s0, s0, 0xEAE0 801F81E4: SLL v0, s5, 0x10 //v0 = tổng pixel chiều cao <<16 ANDI v1, s3, 0xFFFF //s3: tổng pixel độ rộng của chuỗi ORA v0, v0, v1 ADDU a0, s2, r0 ADDU a1, s1, r0 LW a3, 0x5C(sp) ADDU a2, s0, r0 //chuyển giá trị text sang a2 JAL 801F16D8 SW v0, 0x10(sp) //ghi tổng pixel vào 0x10(sp) ADDU s2, v0, r0 ADDIU s1, s1, 0x14 JAL 8002E3EC ADDU a0, s0, r0 J 801F1804 //đọc byte tiếp theo trong chuỗi ADDU s3, s3, v0 org $801F6D8 ADDU t0, a0, r0 ADDIU v0, r0, 0x04 //v0=4 SB v0, 0x03(a1) SLL v1, a1, 0x08 SWL t0, 0x2(a1) ADDU t0, v0, r0 ANDI v0, a2, 0x01 //giá trị text AND với 0x1 để biết đó là Hiragana hay Katakana BEQ v0, r0, 801F1700 ADDIU a0, r0, 0x3812 //lấy hình ảnh Hiragana ADDIU a0, r0, 0x3852 801F1700: SRL v1, a3, 0x03 ANDI a3, a3, 0x07 ADDU v0, a0, v0 BEQ v1, r0, 801F1728 SH v0, 0x0E(a1) LUI v0, 0x8008 LW a3, 0x26B4(v0) J 801F1734 LUI v0, 0x303C 801F1728: LUI v0, 0x8008 LW a3, 0x26B0(v0) LUI v0, 0x30C3 ORI v0, v0, 0x0C31 SRA a0, a2, 0x01 MULT a0, v0 LUI v0, 0x0C ORI v0, v0, 0x0C SW v0, 0x10(a1) SW a3, 0x04(a1) LW v0, 0x10(sp) NOP SW v0, 0x08(a1) SRA v0, a2, 0x1F MFHI t1 SRA v1, t1, 0x02 SUBU v1, v1, v0 SLL v0, v1, 0x02 ADDU v0, v0, v1 SLL v0, v0, 0x02 ADDU v0, v0, v1 SUBU a0, a0, v0 SLL v1, v1, 0x08 OR a0, a0, v1 SLL v0, a0, 0x01 ADDU v0, a0, v0 SLL v0, v0, 0x02 SH v0, 0x0C(a1) JR ra ADDU v0, t0, r0 org $8002E3EC ANDI v0, a0, 0x400 BEQ v0, r0, 8002E404 LUI v0, 0x8008 ANDI a0, a0, 0x03FF J 8002E40C ADDIU v1, v0, 0x23BC 8002E404: LUI v0, 0x8008 ADDIU v1, v0, 0x21F8 //v1= 800821F8, địa chỉ khối dữ liệu độ rộng SRA v0, a0, 0x01 //giá trị text chia đôi vì độ rộng 1 ký tự = giá trị 1 nibble trong byte ADDU v0, v1, v0 //địa chỉ độ rộng = 800821F8 + giá trị nibble của text LBU v1, 0x00(v0) //đọc độ rộng ANDI v0, a0, 0x01 //xác định độ rộng là của ký tự Hiragana hay Katakana BEQ v0, r0, 8002E428 NOP SRL v1, v1, 0x04 8002E428: JR ra ANDI v0, v1, 0x0F //bỏ 1 nibble 4. Font phụ Ngoài bộ font chính có kích cỡ 12 x 12 pixel được dùng trong phần thoại của Field, Battle, World Map và một số phần ở Menu thì FF8 còn sử dụng một bộ font phụ có kích cỡ 8 x 8 pixel trong một số phần của Menu. Tên của G.F. trong Menu kết nối (Junction) là một trong số những phần được thể hiện bằng bộ font phụ này. Bộ font phụ này cũng chính là hình ảnh tim đầu tiên ta tìm được trong CD nếu scan bằng những công cụ như tim2view. Và cũng như bộ font chính, bộ font phụ là kiểu hình ảnh 4 bpp, trong đó gồm 1 bit plane cho kiểu chữ Hiragana và 1 bit plane cho kiểu Katakana. Bằng cách chỉnh sửa nội dung của bộ font phụ này thành ký tự La Tinh thì ta có thể biến tên G.F. và những phần khác trong Menu thành tiếng Việt/Anh. Nhưng trước hết, có một số yếu tố khác ngoài hình ảnh của font chữ mà ta cần phải quan tâm. Khi CPU đọc chuỗi ký tự trong Menu thì nó xử lý qua các giai đoạn như bên dưới (ví dụ về các chuỗi ký tự "ジャンクション", "はずす", "さいきょう", "アビリティ"). 1) Giai đoạn 1: đọc ID của chuỗi text, lấy địa chỉ text org $801F1050 SLL a1, a1, 0x01 //a1: ID của chuỗi ký tự (00:ジャンクション, 01:はずす,...), ID này dẫn tới pointer ADDU v1, a0, a1 //a0: địa chỉ bắt đầu của khối text, gồm cả pointer ADDIU v1, v1, 0x02 //Pointer dẫn tới các chuỗi ký tự bắt đầu ở byte #02 trong khối dữ liệu LHU v0, 0x00(v1) //đọc giá trị pointer NOP BNE v0, r0, 801F1070 //nếu pointer khác zero thì thoát khỏi routine này ADDU v0, a0, v0 //cộng giá trị pointer vào địa chỉ bắt đầu khối dữ liệu để được địa chỉ bắt đầu của chuỗi text ADDIU v0, r0, r0 //v0 = zero 801F1070: JR ra NOP 2) Giai đoạn 2: đọc chuỗi text, căn chỉnh vị trí chuỗi text Sau khi thoát khỏi routine trên, CPU sẽ đọc từng ký tự trong chuỗi cho đến khi gặp control code báo kết thúc chuỗi (0x00). Mục đích của phần xử lý này là để đếm xem chuỗi đó có bao nhiêu ký tự, rồi từ đó tính vị trí trình bày chuỗi tiếp theo lên màn hình ở giai đoạn sau đó. org $801F61C0 ADDU a0, v0, r0 //a0 = v0 = địa chỉ bắt đầu của chuỗi text ADDU v1, r0, r0 //v1 = zero: bộ đếm ký tự 801F61C8: LBU v0, 0x00(a0) //đọc byte tại địa chỉ text NOP BEQ v0, r0, 801F61E0 //xử lý kết thúc chuỗi ở $801F61E0 ADDIU a0, a0, 0x01 //tăng địa chỉ bắt đầu text thêm 1 byte J 801F61C8 //lặp lại chu trình đọc text ADDIU v1, v1, 0x01 //tăng giá trị của bộ đếm ký tự 801F61E0: SLL v1, v1, 0x03 //giá trị bộ đếm x 8, vì mỗi ký tự chiếm 8 pixel chiều ngang ADDIU v1, v1, 0x0C //cộng thêm 12 pixel khoảng cách giữa các chuỗi ADDU s2, s2, v1 //s2: số pixel khoảng cách giữa các chuỗi ký tự SH s2, 0x00(s0) //ghi số pixel khoảng cách vào địa chỉ ở s0 ADDIU s0, s0, 0x02 //tăng 2 byte vào địa chỉ s0 J 801F6198 //xử lý chuỗi ký tự tiếp theo ADDIU s3, s3, 0x01 Từ đoạn xử lý trên thì ta dễ dàng chỉnh sửa được khoảng cách giữa các ký tự trong chuỗi, cũng như khoảng cách giữa các chuỗi ký tự với nhau. 3) Giai đoạn 3: xuất ký tự ra màn hình Sau giai đoạn tính toán vị trí text thì CPU sẽ đọc lại chuỗi text lần nữa rồi xử lý những gì được xuất ra màn hình ở bước tiếp theo. org $8002C5A8 LBU v1, 0x00(t3) //t3: địa chỉ bắt đầu của chuỗi text NOP BEQ v1, r0, 8002C6C0 //nếu ký tự là 00 thì kết thúc đọc chuỗi ADDIU t3, t3, 0x01 //tăng địa chỉ text lên 1 byte SLTIU v0, v1, 0x19 //set v0 nếu giá trị text nhỏ hơn 0x19 BNE v0, r0, 8002C5A8 //v1 nhỏ hơn 0x19 thì rẽ đến 8002C5A8 SLTIU v0, v1, 0x20 //set v0 nếu giá trị text nhỏ hơn 0x20 BEQ v0, r0, 8002C5E8 //nếu là ký tự thông thường (0x20 trở lên) thì rẽ đến 8002C5E8 NOP ADDIU v1, v1, 0xFFE8 //giá trị control code trừ 0x17 SLL v0, v1, 0x03 //v0 = v1 <<3 SUBU v0, v0, v1 SLL v1, v0, 0x05 LBU v0, 0x00(t3) ADDIU t3, t3, 0x01 ADDU v1, v1, v0 8002C5E8: ADDIU v1, v1, 0xE0 //v1 = giá trị text + 0xE0 SLTIU v0, v1, 0x0200 //set v0 nếu v1 nhỏ hơn 512 BEQ v0, r0, 8002C6B8 //nếu v1 (tọa độ ký tự) lớn hơn 512 pixel thì đến 8002C6B8, còn ký tự Kana thông thường luôn nhỏ hơn 512 LUI v0, 0x8005 ADDIU t0, v0, 0x28A8 //t0 = 800528A8: table chứa tọa độ từng ký tự trong Vram SLL v0, v1, 0x02 //v0 = tọa độ ký tự x 4 ADDU v0, v0, t0 //v0 = địa chỉ chứa tọa độ của ký tự tương ứng LW v0, 0x04(v0) //v0 = pointer dẫn tới từng ký tự ADDU t2, a1, r0 //t2 = a1 SRL t1, v0, 0x10 //t1 = pointer >>16 để lấy byte thứ #3 ANDI v0, v0, 0xFFFF //giữ 2 byte cuối trong tọa độ ký tự ADDU t0, v0, t0 //t0 = tọa độ trên + 800528A8: địa chỉ table SLL v0, s2, 0x07 //v0 = s2 x 128 để đổi CLUT màu BLEZ t1, 8002C6B4 // rẽ đến 8002C6B4 nếu tọa độ ký tự >>16 không lớn hơn zero ADDIU v0, v0, 0x0002 //CLUT + 2 SLL t4, v0, 0x10 // t4 = (CLUT + 2) <<16 ADDIU a1, a1, 0x000A LW v0, 0x00(t0) //v0 = tọa độ dấu trọc âm/bán trọc âm và phần Kana NOOP Qua phần xử lý trên thì ta có thể chỉnh sửa giá trị byte nào chỉ đến ký tự nào trong bảng font phụ bằng cách sửa đổi các giá trị ở table $800528A8.
Góp vui với bạn SCP700 một clip, tôi thì không nghiên cứu kỹ thuật bản PSX, lúc rỗi rãi thì nghiên cứu bản PC. Phép lạ mà bạn nói ở trên, là các skill của kẻ địch sẵn có trong game. Nó có thể mix vào Battle Item, hay Magic, tuỳ sở thích, Squall cũng có thể sử dụng Burning Rave hay Meteor Barret của Zell ( Mix finisher move đó vào Item...Hoặc có thể gọi Odin, Gilgamesh thông qua Item , Magic....) Đây là một ví dụ về lập trình lệnh mới cho Omega, trích xuất từ file battle.fs, mã c0m114.dat.
Video cho thấy quá trình tính toán lượng sát thương trong FF8 (bản PlayStation 1999) diễn ra trước khi đòn đánh bắt đầu khá lâu. Lượng sát thương được tính toán ngay khi chọn Command, khá lâu trước khi đòn đánh được triển khai. Những cảnh chiến đấu sau đó chỉ là diễn lại kết quả tính toán mà thôi.
Cái này là tôi mới lập trình mỗi Omega, chưa hoàn thiện cả game, up clip cho vui thôi (bản demo, chứ bản thật, chém khỏe thế thì cả game nát hết). Nếu mất công up lên đây, tôi cần thiết lập lại sức mạnh khu đền Bahamut, Ultima, quái trên đảo tử thần, chùm cuối Ultimecia (những địa điểm vốn phải rất mạnh) cho hợp lý.