Skip to content

Commit

Permalink
StudioSeldomAdventureSystem新增其他(如控制文本框位置)文本处理
Browse files Browse the repository at this point in the history
  • Loading branch information
Darkness-TX committed Jul 22, 2020
1 parent 7d7d653 commit cde13fb
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 2 deletions.
2 changes: 1 addition & 1 deletion NeXAS/BALDR_HEART/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ tutorial如果想还原原字体效果,需要在fnt_make_bold_ft.exe生成png

字体对应.txt为找到的fnt在游戏中使用到的地方,并非所有fnt都会使用,NeXAS_fnt_Shift-JIS.txt为所有fnt的编码对应,tbl_chs.txt用于生成中文字库使用的码表,可自行更改,本项目中使用的tbl.txt和tbl_chs.txt都为针对BALDR HEART制作。

最好都用freetype2版的程序(有ft标志),非freetype2的程序后续并没有开发,因为用Windows API生成的效果巨 屎 无 比,所有抛弃了,仅供参考。
最好都用freetype2版的程序(有ft标志),非freetype2的程序后续并没有开发,因为用Windows API生成的效果巨 屎 无 比,所以抛弃了,仅供参考。
#### [游戏主程序]
用的Themida壳,脱壳就顺带也破解了.....,根据dump的方法不同,可能需要自行修复一下IAT表,一般会少了D3DXAssembleShader、D3DXQuaternionMultiply,exe中有非常多文本,想完美汉化不得不脱壳。
#### [文本]
Expand Down
81 changes: 81 additions & 0 deletions StudioSeldomAdventureSystem/SEC5_CODE_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
str_op_name2 = b'\x24\x13\x01\x3C\x50\x13\x03\x24\x1E\x00\x00\x00\x00'
#与人名1配套 $n3<>n3$ 其中一个用处是控制多人说同一句话时对话框四散在画面上
str_op_name3 = b'\x1B\x82\x02\x00'
#与控制文本框位置用人名及立绘效果用人名配套 $n4<>n4$
str_op_name4 = b'\x20\x79\x00\x00\x00\x50\x23\x50\x13\x01\x24\x1E\x00\x00\x00\x00'
#与人名1配套 $n5<>n5$ 其中一个用处是控制对话框跟随人物在画面中的位置
str_op_name5 = b'\x20\x77\x00\x00\x00\x50\x23\x50\x13\x01\x24\x1E\x00\x00\x00\x00'
#其他人名 $on<>on$
str_op_other_name = b'\x50\x23\x50\x13\x01\x24\x1E\x00\x00\x00\x00'
#控制文本框位置用人名 $cn<>cn$
str_op_control = b'\x1B\x86\x02\x00'
#立绘效果用人名 $en<>en$
str_op_effect = b'\x1B\x80\x02\x00'
#特殊用途人名 $p<>p$ 前4字节记录整块长度(FastForwardOffAtSelection、MsgColorsByName、InterpolatePicture)其中MsgColorsByName为文字颜色根据人物变化功能,可在游戏设置中开启
str_special_name = b'\x2A\x02\x13\x01\x24\x3A\x1E\x00\x00\x00\x00'
#章节名 $c<>c$ 前4字节记录整块长度
Expand Down Expand Up @@ -148,6 +158,72 @@ def find_name3(data):
byte_off[str_opcode_start] = (len(byte_list) - 1, byte2int(data[str_offset_start:str_offset_start + 4]) + 4 + 4, num)
str_offset_start = data.find(str_op_name3, str_offset_end)

def find_name4(data):
str_offset_start = data.find(str_op_name4)
while str_offset_start != -1:
str_opcode_start = str_offset_start - 4
str_offset_start += len(str_op_name4)
num = byte2int(data[str_offset_start:str_offset_start + 4])
str_offset_end = str_offset_start + 4 + num
byte_list.append('$n4<'.encode('932') + data[str_offset_start + 4:str_offset_end] + '>n4$'.encode('932'))
byte_off[str_opcode_start] = (len(byte_list) - 1, byte2int(data[str_opcode_start:str_opcode_start + 4]) + 4, num)
str_offset_start = data.find(str_op_name4, str_offset_end)

def find_name5(data):
str_offset_start = data.find(str_op_name5)
while str_offset_start != -1:
str_opcode_start = str_offset_start - 4
str_offset_start += len(str_op_name5)
num = byte2int(data[str_offset_start:str_offset_start + 4])
str_offset_end = str_offset_start + 4 + num
byte_list.append('$n5<'.encode('932') + data[str_offset_start + 4:str_offset_end] + '>n5$'.encode('932'))
byte_off[str_opcode_start] = (len(byte_list) - 1, byte2int(data[str_opcode_start:str_opcode_start + 4]) + 4, num)
str_offset_start = data.find(str_op_name5, str_offset_end)

def find_other_name(data):
str_offset_start = data.find(str_op_other_name)
while str_offset_start != -1:
str_opcode_start = str_offset_start - 5 - 4
str_offset_start += len(str_op_other_name)
num = byte2int(data[str_offset_start:str_offset_start + 4])
str_offset_end = str_offset_start + 4 + num
if num != 0 and str_opcode_start not in byte_off:
byte_list.append('$on<'.encode('932') + data[str_offset_start + 4:str_offset_end] + '>on$'.encode('932'))
byte_off[str_opcode_start] = (len(byte_list) - 1, byte2int(data[str_opcode_start:str_opcode_start + 4]) + 4, num)
str_offset_start = data.find(str_op_other_name, str_offset_end)

def find_control(data):
str_offset_start = data.find(str_op_control)
while str_offset_start != -1:
str_opcode_start = str_offset_start
str_offset_start += len(str_op_control)
num = byte2int(data[str_offset_start:str_offset_start + 4])
str_offset_end = str_offset_start + 4 + num
if data[str_offset_end] != 0x01:
print('标识符错误offset:0x%X opcode:0x%X'%(str_offset_end,data[str_offset_end]))
os.system('pause')
exit(0)
str_offset_start2 = str_offset_end + 1 + 4 + len(op_num_split)
num = byte2int(data[str_offset_start2:str_offset_start2 + 4])
str_offset_end2 = str_offset_start2 + 4 + num
byte_list.append('$cn<'.encode('932') + data[str_offset_start2 + 4:str_offset_end2] + '>cn$'.encode('932'))
block_num = len(str_op_control) + 4 + byte2int(data[str_offset_start:str_offset_start + 4]) + 1 + 4 + byte2int(data[str_offset_end + 1:str_offset_end + 1 + 4])
byte_off[str_opcode_start] = (len(byte_list) - 1, block_num, num)
str_offset_start = data.find(str_op_control, str_offset_end)

def find_effect(data):
str_offset_start = data.find(str_op_effect)
while str_offset_start != -1:
str_opcode_start = str_offset_start
str_offset_start += len(str_op_effect)
num = byte2int(data[str_offset_start:str_offset_start + 4])
str_offset_end = str_offset_start + 4 + num
str_offset_start2 = str_offset_start + 4 + len(op_num_split)
num = byte2int(data[str_offset_start2:str_offset_start2 + 4])
byte_list.append('$en<'.encode('932') + data[str_offset_start2 + 4:str_offset_start2 + 4 + num] + '>en$'.encode('932'))
byte_off[str_opcode_start] = (len(byte_list) - 1, byte2int(data[str_offset_start:str_offset_start + 4]) + 4 + 4, num)
str_offset_start = data.find(str_op_effect, str_offset_end)

def find_special_name(data):
str_offset_start = data.find(str_special_name)
while str_offset_start != -1:
Expand Down Expand Up @@ -449,8 +525,13 @@ def CODE_dump():
find_name1(data)
find_name2(data)
find_name3(data)
find_name4(data)
find_name5(data)
find_control(data)
find_effect(data)
find_special_name(data)
find_chapter(data)
find_other_name(data)
#find_jump(data)
#check_jump(data)
find_jump_plus(data)
Expand Down
112 changes: 111 additions & 1 deletion StudioSeldomAdventureSystem/SEC5_CODE_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
str_op_name2 = b'\x24\x13\x01\x3C\x50\x13\x03\x24\x1E\x00\x00\x00\x00'
#与人名1配套 $n3<>n3$ 其中一个用处是控制多人说同一句话时对话框四散在画面上
str_op_name3 = b'\x1B\x82\x02\x00'
#与控制文本框位置用人名及立绘效果用人名配套 $n4<>n4$
str_op_name4 = b'\x20\x79\x00\x00\x00\x50\x23\x50\x13\x01\x24\x1E\x00\x00\x00\x00'
#与人名1配套 $n5<>n5$ 其中一个用处是控制对话框跟随人物在画面中的位置
str_op_name5 = b'\x20\x77\x00\x00\x00\x50\x23\x50\x13\x01\x24\x1E\x00\x00\x00\x00'
#其他人名 $on<>on$
str_op_other_name = b'\x50\x23\x50\x13\x01\x24\x1E\x00\x00\x00\x00'
#控制文本框位置用人名 $cn<>cn$
str_op_control = b'\x1B\x86\x02\x00'
#立绘效果用人名 $en<>en$
str_op_effect = b'\x1B\x80\x02\x00'
#特殊用途人名 $p<>p$ 前4字节记录整块长度(FastForwardOffAtSelection、MsgColorsByName、InterpolatePicture)其中MsgColorsByName为文字颜色根据人物变化功能,可在游戏设置中开启
str_special_name = b'\x2A\x02\x13\x01\x24\x3A\x1E\x00\x00\x00\x00'
#章节名 $c<>c$ 前4字节记录整块长度
Expand Down Expand Up @@ -210,6 +220,30 @@ def build_opcode():
elif str_list[i].find('$n2<') != -1:
#line = replace_line(org_list[i].replace('$n2<','').replace('>n2$','').encode('932'))
line = replace_line(str_list[i].replace('$n2<','').replace('>n2$','').encode('936'))
#人名3
elif str_list[i].find('$n3<') != -1:
#line = replace_line(org_list[i].replace('$n3<','').replace('>n3$','').encode('932'))
line = replace_line(str_list[i].replace('$n3<','').replace('>n3$','').encode('936'))
#人名4
elif str_list[i].find('$n4<') != -1:
#line = replace_line(org_list[i].replace('$n4<','').replace('>n4$','').encode('932'))
line = replace_line(str_list[i].replace('$n4<','').replace('>n4$','').encode('936'))
#人名5
elif str_list[i].find('$n5<') != -1:
#line = replace_line(org_list[i].replace('$n5<','').replace('>n5$','').encode('932'))
line = replace_line(str_list[i].replace('$n5<','').replace('>n5$','').encode('936'))
#其他人名
elif str_list[i].find('$on<') != -1:
#line = replace_line(org_list[i].replace('$on<','').replace('>on$','').encode('932'))
line = replace_line(str_list[i].replace('$on<','').replace('>on$','').encode('936'))
#控制文本框位置用人名
elif str_list[i].find('$cn<') != -1:
#line = replace_line(org_list[i].replace('$cn<','').replace('>cn$','').encode('932'))
line = replace_line(str_list[i].replace('$cn<','').replace('>cn$','').encode('936'))
#立绘效果用人名
elif str_list[i].find('$en<') != -1:
#line = replace_line(org_list[i].replace('$en<','').replace('>en$','').encode('932'))
line = replace_line(str_list[i].replace('$en<','').replace('>en$','').encode('936'))
#特殊用途人名
elif str_list[i].find('$p<') != -1:
#line = replace_line(org_list[i].replace('$p<','').replace('>p$','').encode('932'))
Expand Down Expand Up @@ -343,6 +377,82 @@ def CODE_import():
offset_index,address_index = change_jump(str_num,len(line),end,offset_index,address_index)
line = str_op_name3 + int2byte(len(op_num_split) + 4 + len(line) + len(buff)) + op_num_split + int2byte(len(line)) + line + buff
dst.write(line)
#人名4
elif str_list[i].find('$n4<') != -1:
if str_list[i].count('$n4<') != str_list[i].count('>n4$'):
print('编号%d行前后标识符不匹配!%s'%(i,str_list[i]))
os.system('pause')
exit(0)
#line = replace_line(org_list[i].replace('$n4<','').replace('>n4$','').encode('932'))
line = replace_line(str_list[i].replace('$n4<','').replace('>n4$','').encode('936'))
block_num = int(script_list[i].split('|')[1]) - 4
str_num = int(script_list[i].split('|')[2])
buff = data[end + 4 + len(str_op_name4) + 4 + str_num:end + 4 + block_num]
offset_index,address_index = change_jump(str_num,len(line),end,offset_index,address_index)
line = str_op_name4 + int2byte(len(line)) + line + buff
dst.write(int2byte(len(line)))
dst.write(line)
#人名5
elif str_list[i].find('$n5<') != -1:
if str_list[i].count('$n5<') != str_list[i].count('>n5$'):
print('编号%d行前后标识符不匹配!%s'%(i,str_list[i]))
os.system('pause')
exit(0)
#line = replace_line(org_list[i].replace('$n5<','').replace('>n5$','').encode('932'))
line = replace_line(str_list[i].replace('$n5<','').replace('>n5$','').encode('936'))
block_num = int(script_list[i].split('|')[1]) - 4
str_num = int(script_list[i].split('|')[2])
buff = data[end + 4 + len(str_op_name5) + 4 + str_num:end + 4 + block_num]
offset_index,address_index = change_jump(str_num,len(line),end,offset_index,address_index)
line = str_op_name5 + int2byte(len(line)) + line + buff
dst.write(int2byte(len(line)))
dst.write(line)
#其他人名
elif str_list[i].find('$on<') != -1:
if str_list[i].count('$on<') != str_list[i].count('>on$'):
print('编号%d行前后标识符不匹配!%s'%(i,str_list[i]))
os.system('pause')
exit(0)
#line = replace_line(org_list[i].replace('$on<','').replace('>on$','').encode('932'))
line = replace_line(str_list[i].replace('$on<','').replace('>on$','').encode('936'))
block_num = int(script_list[i].split('|')[1]) - 4
str_num = int(script_list[i].split('|')[2])
buff = data[end + 4 + 5 + len(str_op_other_name) + 4 + str_num:end + 4 + block_num]
offset_index,address_index = change_jump(str_num,len(line),end,offset_index,address_index)
line = data[end + 4:end + 4 + 5] + str_op_other_name + int2byte(len(line)) + line + buff
dst.write(int2byte(len(line)))
dst.write(line)
#控制文本框位置用人名
elif str_list[i].find('$cn<') != -1:
if str_list[i].count('$cn<') != str_list[i].count('>cn$'):
print('编号%d行前后标识符不匹配!%s'%(i,str_list[i]))
os.system('pause')
exit(0)
#line = replace_line(org_list[i].replace('$cn<','').replace('>cn$','').encode('932'))
line = replace_line(str_list[i].replace('$cn<','').replace('>cn$','').encode('936'))
block_num = int(script_list[i].split('|')[1]) - 4
str_num = int(script_list[i].split('|')[2])
num = byte2int(data[end + len(str_op_control):end + len(str_op_control) + 4])
buff = data[end:end + len(str_op_control) + 4 + num + 1]
dst.write(buff)
offset_index,address_index = change_jump(str_num,len(line),end,offset_index,address_index)
line = op_num_split + int2byte(len(line)) + line + b'\xFF'
dst.write(int2byte(len(line)))
dst.write(line)
#立绘效果用人名
elif str_list[i].find('$en<') != -1:
if str_list[i].count('$en<') != str_list[i].count('>en$'):
print('编号%d行前后标识符不匹配!%s'%(i,str_list[i]))
os.system('pause')
exit(0)
#line = replace_line(org_list[i].replace('$en<','').replace('>en$','').encode('932'))
line = replace_line(str_list[i].replace('$en<','').replace('>en$','').encode('936'))
block_num = int(script_list[i].split('|')[1])
str_num = int(script_list[i].split('|')[2])
buff = data[end + len(str_op_effect) + 4 + len(op_num_split) + 4 + str_num:end + block_num]
offset_index,address_index = change_jump(str_num,len(line),end,offset_index,address_index)
line = str_op_effect + int2byte(len(op_num_split) + 4 + len(line) + len(buff)) + op_num_split + int2byte(len(line)) + line + buff
dst.write(line)
#特殊用途人名
elif str_list[i].find('$p<') != -1:
if str_list[i].count('$p<') != str_list[i].count('>p$'):
Expand Down Expand Up @@ -382,7 +492,7 @@ def CODE_import():
str_num = int(script_list[i].split('|')[2])
#line = replace_line(org_list[i].encode('932'))
line = replace_line(str_list[i].replace('♪','♂').encode('936'))
#if i <= 5536 or i >= 5538:
#if i <= 754 or i >= 756:
# line = replace_line(org_list[i].encode('932'))
#else:
# line = replace_line(str_list[i].replace('♪','♂').encode('936'))
Expand Down

0 comments on commit cde13fb

Please sign in to comment.