Romhacking in Tales of Destiny 2
So once again I open a romhacking thread surprised after finding absolutely no interest by the fanbase in a game translation project that has been requested quite a lot of time ¿"?...
I'm talking about Tales of Destiny 2 (available for both PSP and PS2). Several weeks ago I hacked it (again) and tweeted to see how good reception would be for the project. Believe or not it was pretty bad: only a few people answered and I even lost many followers right after tweeting xDD.
That being said, I'm posting some romhacking stuff here, mostly so everything done wasn't a waste of time.
Just like with Type-0, this is not a recruitment thread, but if someone forms a translation team they can count with my help. As of now, there are no plans of going forward with the translation (at least into English, there are some people interested in translating the game into Spanish), so I'm pretty much leaving the last chance in the hands of the fans, once again.
So, getting started: Both versions of the game works exactly the same way, regardless of the content (that was updated in the PSP version) so unless stated otherwise, everything said here applies for both PSP and PS2 versions.
The first thing is, of course, having a look at the game's files. Right after opening the disc (or a disc image) we can see:
-The game's executable file (the ELF)
-A big file, "file.fbp" containing most of the game ressources
-Video files.
As you can guess, video files are just pre rendered scenes, with voice over and no subtitles at all.
They are pretty easy to edit so inserting subtitles is perfectly possible.
Then we have the big FBP file. This one does not include information to unpack the files inside. Instead, we need to check the executable for it. Inside the ELF there is a pointer table that specifies all file offsets in the FBP file, along with some flags:
Each entry of the able consist in:
- A 21 bit offset -> the file offset inside the FBP
- 11 bits for flags -> Compression, file type, etc...
In order to extract the big file, one would calculate each file size based on the next file's offset. That is enough to extract the whole FBP. Reverting the process it would be easy to repack it.
Once extracted all files we can see the game's raw resources in some custom formats.
The very first file in the package follows the basic data structure used for compressed files in ToD2:
- 1 byte -> compression ID
*** 0x00 For uncompressed files
*** 0x01 For LZSS
*** 0x03 For LZSS + RLE
*** 0x04 For ZLIB (PSP Only)
- 4 bytes -> compressed size
- 4 bytes -> uncompressed size
- Rest of the data -> File data
Does that ring a bell? This is very similar to many other old school JRPG's, where LZSS and RLE are mixed (many SNES, N64, and pretty much all Tri-Ace game do this, we are only missing huffman in ToD2 ).
One peculiarity is that the data is not 32-bit aligned. How could a 32 bit MIPS processor read this? Believe it or not, the game's ASM code shows that it read byte per byte, storing them in the stack in aligned positions, and then read the 32 bit integer from the stack. This shows that the game was coded keeping memory optimization in mind.
After decompressing the file, we obtain some raw data that appears to follow the pattern of a 8 bit graphic.
We can try giving it X and Y sizes, and a grayscale palette, we then unswizzle it and... VOILA! IT'S THE FONT!
http://s9.postimg.org/6gxqt0a9b/FNT.png
It incudes a TON of characters, but no lowercase letter except for some at the bottom (does the PS2 version have eyetoy functionality? If it doesn't it was clearly planned at some point).
The second file in the FBP is a raw shift-jis buffer, easy to decode:
Code:
,.・:?!ー/”()%0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろ+わ「」をんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミ&ムメモャヤュユョヨラリルレロ-ワ=☆ヲンヴ △○×<>♪~▽『』、。一二十千万地水火風光闇南西北赤白黒年月日時戦闘攻撃防御回避術技道具合成神座都市格先行世楽園案外所知大昔人間自分生毎祈決上降今度来待乗空何手入以持武器屋教会食材宿客室階廊下変第章代更広場旧街前悪夢帰王開放土新活気住恩最近国団進出信助話顔心底城音聞急身賊込狙率精鋭保証襲負傷奪言英雄男見目朝早女子止殿向雪書界中思泣馬足恋盗現歌隠事情色感動運命明寒暖房図館本読番単文化民与建歴史的美私語禁公静落方爆発起直後戻好乱終平和若旅諸温育机学葉庶政治必要我視察笑遠存在危険彼野望積到着遅誘導家小社廃坑宝部悔特別暗号者繁栄願記貧富差税制弱救済予算確安守警組織支援意識改革愛条想素敵当考誤理実即効性求劇薬選約束届型引力作内設備数枚句仕幸奥採掘探掛未稼略切替電源右段突壁調港船定期長修菜商品台不故側責任処欲海路他法退屈失礼腕立芸受参然勇折越印陸暮準飛振応使僕頼企業滅金庫収霧眠依申遺産状貴様偶主取跡敷買途死被害売配晴装飾名工嬢石箱渡結局比山疲端位置町俺仮面臣逃秘密多仲経追相返父少関係形歩論夜休指覚君体全包浮無郷同普通元寝付絶対勝利詳忘兄婚田舎村親声叫打兵士機派晩泊似母連用達息尊敬遊観強倉怪物倒沈問題脱員程犠牲割操舵激初航続補寸際照完舞等由難認得件審次幹崩壊共歳原因真協説唯預没態談羽潮香議軽伝絡張増損呼油断穴鼻興味便拝堂線簡供騎属敗走集背景果停煮炒米緒役熱鮮料揚口卵焼抜肉統加減賞太刺烈夏浴波漂幻酔瞬魚重深冷宇宙星輝豪快麻婆豆腐辛妙極違異魔養豊盛絵画描構甘巻染高互称誰幼頃演汁介類腹式吸酸清奇贈飲熟須交響曲奏速半拡縮了径冒賛離迷惑孤児院孝逆転塔報査隊護衛価値紙苦慣血流労惜捨質胸整店踏巨破衣犯捕牢始嫌過去功績両貸耳趣剣幕誓歯眼悟吹昨玉送字暴里恐謝聖総適順納捧偉祝福痛友髪短残念抱悩砕威勢僧正解虫仇討払黙示従忙謁週毒頭驚有荒復境遇健康病影硬慮雲訳許換拒災拠肩可能偽善鳥巣憧資誇管量縁愚邪容赦像仰困択夕扱啓汚罰胆猫棒細点製矢居肝答義務留障訓弟妹首迎姉姿将散練猟働例志判冗官臨刻潜服余計争悲閉永耐移候習罪独昼反氷妻注表究徳刃倍洗缶押登提常刀怒才木彫夫婦花鳴祭騒況嫉妬借寄茶酒燃投希費並喜辺仔徴坊飼肖博天軍祖棚講呪医勉布訪混侵疑儀努益門試厳裏腰帥封柱繋丘畑忍厄嫁展汗車接絹肌魂票橋娘根怖幅衝射罠床丈区随枝古頂横拾良穫承森雑貨族省掃除粧恥濯帯策裕施営優骨埋躍冬遙圧迫獄再亡雨枯噴久衰鈍凍昇低砂含晶溜珠黄霊召喚蒼紅翠草種瓶鱗珍獣蓋鑑欠各煙筒造炭炉槽苗植周囲鍵級干匂涙球漬瓜臭毛芳皮丸牛乳酵胃腸炊穀農八孫柔麦粉般脂肪塊塗雅斬基偃厚雰典湾鎌殺尾冠匠鍛旋誉炎竜爪隼紋創牙岩剛柩副葬鋼易裂妖稲慈忠円卓帝嵐乙杖職殴権標笏狂節孔雀如角青紡慟哭銀左東蛮錫匹蛇祓詠唱柄斧槍槌叉矛鉄陣賜堅固杭灰冶科駆逐逸骸緑薙傑狩弓弾扉貫鎧七軌吐尽浄環縫板糸甲殊継塞赴網編洋島巫兜頬築頑漢帽薄濃愉輪及喰鮫致鉈駄篭授袋瑠璃佐賢癒偏疾巧伴徐縞瑪瑙験華姫象靴膝蹴枠謎隣徒携塵繰翔閃渦纏垂屠龍叩片跳招規模雷鐘震撼範複弧距鉱棺焉裁漆淵系列限控満隔嘘漏披露令抵抗痺僅延秒縛遭促械瀕微熊洞窟消三々★z…壺鎚亜翼殻棲爬閲覧個削辞揺魅哀検還艇獲憎恵稽磨銘侍緊壺鎚亜翼殻棲爬閲覧個削瞳墜燐砲双拳覆推測貼触憶讃非握映写渉軸述粋妨吉鍋銅柳丁凶陽河脈超領域飯寿餓司荷担臓ヶ告析透筋励看皿誌碑焚萌吼齢陛姑歓挨拶繊粛専己紹粗往郎懸逢瀬杯岸泳詰耗酬噛虚蓮踊拓崇伸芝脚四墓駒卑劣末克否旗秩序絆酷層研媒閣巡駐屯挑慎臆怯揮謹誕班攪戒老排伏刑乾陥乞至聴符宣脳凌駕歪mkg把漠隆録徹氏撹阻渇讐恨却顛岐哲凝彗膨陰謀川沿泉犬璧傲慢鹿委憩扇給冑宮紫燭灯憐舗菌課庭衆厨遥仙央湯呂浸寺挿昏為刷暑季償奴捜財奉師購療池羅憂評噌轟五縦輩勅請棄惧監滝銭奮純塹壕郭貯蔵斉維校錬挺猟尉佳慌遂凄炸昌耕批宗爺礎糧蓄輸艦搭載勧卒噂湖宅勤猛皆潔鏡麗曹玄寂壇堕架擬銃貢献砦隅詩吟著膠占百傘敢惨索樹林遮涼粒拍楼鎮牧朴盾核皇律倶幽某淑六冥井戸懐充軟冊僚弁詞督滞慕嘆溶卸兼晰煥凡釣秋洒羊呑禄狭童贅沢需滑額袖販帳簿掠陶偵患症咲煎俊版又逝鎖猿窓慨俗睨競紳浪癖掴惚執彷徨楚尋釈札秀肥雌飢繕姓墨慰飽概免疫泥尻脇蒸湿澄征締春曇捉剖謙群暇焦妥俄逮拘脅潤譲肺涯摘芽九撤勘融賭傾匿誠‥叔浜席彩頻壮液墟谷膳仁盆栽培欄鬼縄梯籠京凛刊漫琢刊漫摩煉刹伯蚊脆餌桃廷掲疎沌菓翌愕釜茹針沼紀礁菓寧聡舌菓畳懲契肢藤αβ禍壷馴樺貰馳掟懇嬉挫松鼓較亀貿綿邸雇烏唄剃稿椅旺託盟虐覗戯撮ヱ泡隕磁洩窃滴虎怨凱旦那崖eytoyheart妄鼬也貌髭紛盤苛碧桜丼迅州燥軒
It enumerates all charecters present in the font, so it's most likelly a conversion table used in development stages of the game, to convert the text into the game's custom text encoding. It will come in handy.
In many other project (such as Type-0, Valkyrie Profile, FF4, Star Ocean 1&2, etc...), we didn't have this, and it was necessary to transcribe the font to have it as text (which is some crazy job btw...)
This is everything we need to edit the font. It's actually a must, since we have to add lowercase letters xD.
But what about the rest of the files? Where is the game's script?. In order to find it, we need to dig into some other files, the so-called SCPK files.
SCPK's are "game rooms": individual compiled scripts written in a custom language that manage the game's logic.
I call it rooms because they are are stored in a per-place basis, so you'll always find a SPCK file per game location.
One SCPK will have the code for all events in a given, regardless of the game timeline, as well as all assets present in that place. Again, this "room scheme" is pretty common in old school JRPG games.
Having a look at the data structure, each SCPK file consists on:
- A 4 byte signature "SCPK"
- Two 2 byte integers: Major and minor version numbers (always 0x01 and 0x07).
- A 4 byte integer: number of files packed in the SCPK
- 32 bit padding.
- An integer array: packed files sizes, so it's size is always <number_of_packed_files * 4>
- Packed files, with specified sizes
*** The first file contains the BG graphic data + BG animation data + BG animation code, for example:
*** The second file is always a set of ID's one per remaining file
*** The rest of files, except for the last one contain sprite data (character + effects) and animation code.*** The last file includes the room logic + text script. As I said, it uses a custom language, that the game's interpreter runs. Once again, this happens in many classic JRPG's. In fact, in some cases, fans have been able to understand the custom language and create a fan sequel using the original engine (This is the case of Chrono Trigger: Crimson Echoes).
This last code file (being compiled code) has a complex structure, but since it includes text, there is no choice but to disassemble it; it has:
- 4 bytes: the signature: "SCED"
- A 32 bit value that points to the start of the code section
- Another 32 bit value, this time pointing to the text section
- More pointers until getting to the code section
- The code section itself, it ranges from its pointer to the text sextion pointer
- The text section itself, it ranges from its pointer to the end of the file
A couple of problems here:
-The text uses an incomprehensible encoding, that mixes 8 and 16 bit characters (-_-").
-There are no actual text pointers, but size is limited and not constant... That's because the text position is specified by compiled pointers in the code section... LOL, this hobby can be a pain sometimes xD.
Okay the way to do this is to isolate both the code and the text sections. We case see that the text seems to be separated by byte 0x00, so that would be the end of an intervention (and right after it, the start of the next one):
Knowing where all text interventions start and end, we can look for their offsets in the code sections and... TADA!!
We can find text offsets in the code section of the SCED! Always preceded by byte 0xf8. This is because the code section is an array of "commands".
Each command has:
- A 1 byte opcode
- Several bytes: the operand(s)
For example, opcode 0xf8 means "Open text window" and it uses a 2 byte operand: the text pointer. If we managed to understand all opcodes we could use the game engine to build our own sequel, for example ()"
Still a couple of issues, though
1 - Since opcodes have different size operands, how can we parse the code section to find pointers?
***Possible answer A (dirty one): We just look for the 0xf8 byte in the code section, that's followed by a valid intervention in the text section (e.g. is preceeded by byte 0x00).
***Possible answer B (clean one): We disassemble the SCED interpreter's native MIPS code and write down all possible opcode and operand sizes.
*In the above image, the opcode is located in registry $v1, the code jumps to different places deppending on it's value. In this case $v1 contains the value 0xf8 so it will jump to 0x8951de0, where it'll read two bytes as operand. watching the rest of possible jumps we can know the operand size for each opcode ^^.
As a matter of fact there are several opcodes that configure text appearance, so it's possible to change the text's colors (there are 8 palettes available), it's oppacity, it's x/y offset within the window, it's whith/height, and a long etc... As for window sizes and shapes, they are automatic based on the text to appear on them.
2 - We still don't have a clue about the custom text encoding, how the heck could we edit it?
***Possible answer A (dirty one): We build a table having a look at the raw data and the game's result
***Possible answer B (clean one): We disassemble the tex-decoding routine and implement it. Just like in Type-0 (and many other JRPG games) the result is the position of the character in the font, and since we already have its transcription, we can decode the custom encoding.
*** BTW, the text decoding routine supports ASCII, so upper case letters can be written directly, as for lowercase, the easiest method would be replacing some one-byte hiras in the font
I did several tests of everything after recreating a lowercase font (based on the original typography) and updating the encoding descriptor file:
And that's pretty much it... There are some other interesting files in the game that I already decoded. For example, sound is coded in a pretty simple way, so the game could be dubbed... But since this is already a long post, and it kinda covers the interesting aspects of a possible project, I think I'm just gonna hit that "Create Thread" button and call it a day.
Regards:
~Sky