Chime[RUS]
Зарегистрирован: 31.08.2014 Сообщения: 11
|
Добавлено: Пн Фев 15, 2016 11:15 pm Заголовок сообщения: Дополнительные возможности. Написание плагинов. |
|
|
Документация которую написал Griever была для конкретного случая запаковки. Но прочитать его всё равно полезно, т.к. там подробно описано назначение функций. )
Плагины же бывают разными.
Я попытаюсь систематизировать разновидность одного типа. Он не сложный, но очень неприятно когда проект не работает из-за такой мелочи, как неверно определённый символ разрыва строки. Такое случается довольно часто. Специальные коды в играх иногда содержат довольно много символов и если среди них есть тот, что в таблице обозначен как конец строки, Kruptar режет извлекаемую строку на этом коде и часть данных теряется. Чтобы этого избежать люди придумали вносить подобные коды в исключения при чтении скрипта (см. плагин Griever'а для TP).
На самом деле гораздо проще и правильнее не каждый такой код вносить в исключения, а вычитать из обработки сразу целые семейства кодов. Этому посвящены две темы на форуме MagicTeam: 1 и 2.
Необходимый навык - правильное распознавание контрольных кодов (приходит самостоятельно вместе с опытом: работа с WildCard в Hex-редакторе например или более продвинутые методы).
При составлении таблицы, способ описан в предыдущем руководстве, выясняется нужен ли Kruptar'у плагин или нет.
Если он таки нужен, то понадобится Delphi (Lazarus не пожелал обрабатывать ассемблерные вставки из Needs.pas). Но если очень хочется можно и на Си писать.
Я стараюсь вносить в плагин все найденные типы кодов, вне зависимости от того содержат они символ разрыва или нет. Это позволяет исключить ошибки невнимательности, т.е. если что-то было пропущено мы это увидим в проекте, но проект в любом случае будет работать верно.
Рассматривать будем только функции GetData и GetStrings, т.к. меняются только они и название плагина.
Вот пример плагина для однобайтовой кодировки (здесь Zelda OoT N64) и фрагмент таблицы:
Код: | function GetData(TextStrings: PTextStrings): AnsiString; stdcall;
var
R: PTextString;
begin
Result := '';
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <> NIL do
begin
Result := Result + R^.Str + #2; // код конца строки: 02, можно его и не отображать в проекте.
R := R^.Next
end
end
end;
Function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
var
P: PByte; PC: PChar absolute P;
Len: Byte; Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
P := Addr(ROM[X]);
while P^ <> 0 do
begin
Len := 0; //Обозначаем переменную длины кода, а то вдруг их там нет.
if (P^ = $05) or (P^ = $06) or (P^ = $07) //Здесь идёт перечисление всех первых байтов контрольных кодов (берутся из таблицы)
or (P^ = $0C) or (P^ = $0E) or (P^ = $11) //Если встречается кто-то из них, то нужно прочитать контольный код
or (P^ = $12) or (P^ = $13) or (P^ = $14)
or (P^ = $15) or (P^ = $1E)
then begin
Code := P^; // Запоминаем этот первый байт
Str := Str + PC^; //Записываем его в извлечённый текст (Вот он 1 байт, который не будем учитываеть в Len)
Inc(P); //Переходим к следующему
case Code of //Т.к. зависимость длины кода от каких-то байт в нём обнаружена не была, просто выбираем.
$05,
$06,
$0C,
$0E,
$13,
$14,
$1E: Len := 1; //Если код начинается с $05, $06, $0C, $0E, $13, $14 или $1E то его длина 2 байта, осталось 1 байт считать.
$07,
$11,
$12: Len := 2; //Если код начинается с $07, $11, $12 то длина кода 3, следовательно нужно прочитать ещё 2 байта.
$15: Len := 3 //Если код начинается с $15 то длина его 4, т.е. осталось считать 3 байта.
end;
X := Length(Str); //
SetLength(Str, X + Len); //
Move(P^, Str[X + 1], Len); //
Inc(P, Len); //Здесь считываем нужное количество байт.
end else
if P^ = $02 then Break // это можно написать и здесь: while P^ <> $02 do, но мне обычно лень, т.к. ноль не мешает.
else
begin
Str := Str + PC^; // Обычное чтение, когда никакие контрольные коды не встретились.
Inc(P)
end
end
end
end; |
Фрагмент таблицы
Код: | 0540=[/C]
0541=[Red]
0542=[Green]
0543=[Blue]
0544=[l_Blue]
0545=[Pink]
0546=[Yellow]
0547=[Black]
0602=[sp_01]
0603=[sp_02]
077072=[07_200]
0C0A=[delay_1]
0C14=[delay_2]
1100A0=[11_223]
123880=[snd_04]
1300=[icon_01]
1301=[icon_02]
1302=[icon_03]
1303=[icon_04]
1400=[/slow]
1401=[slow_01]
1402=[slow_02]
1403=[slow_03]
15000110=[BG1]
15002000=[BG2]
1E00=[score_HAR]
1E01=[score_Poe]
1E02=[score_fish]
1E03=[score_Epona]
01
04
ends
02 |
Вот пример чуть более хитрого плагина для однобайтовой кодировки (здесь Zelda MC GBA):
Код: | Function GetData(TextStrings: PTextStrings): AnsiString; stdcall;
var
R: PTextString;
begin
Result := '';
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <> NIL do
begin
Result := Result + R^.Str + #0; // код конца строки: 00, можно его и не отображать в проекте.
R := R^.Next
end
end
end;
Function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
var
P: PByte; PC: PChar absolute P;
Len: Byte; Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
P := Addr(ROM[X]);
while P^ <> 0 do
begin
Len := 0; //Обозначаем переменную длины кода, а то вдруг их там нет.
if (P^ = $01) or (P^ = $02) or (P^ = $03) //Опять идёт перечисление всех первых байтов контрольных кодов
or (P^ = $04) or (P^ = $05) or (P^ = $06) //Если встречается кто-то из них, то нужно прочитать контольный код
or (P^ = $07) or (P^ = $08) or (P^ = $09)
or (P^ = $0C) or (P^ = $0F)
then begin
Code := P^; // Запоминаем первый байт
Str := Str + PC^; //Записываем его в извлечённый текст
Inc(P); //Переходим к следующему
case Code of //Т.к. зависимость длины кода от каких-то байт в нём обнаружена не была, просто выбираем.
$01,
$02,
$06,
$08,
$09,
$0C,
$0F: Len := 1; //Длина этих кодов 2 байта, 1 уже был считан.
$03,
$07: Len := 2; //Длина этих кодов 3 байта, 1 уже был считан.
$04: case P^ of //А вот если код начинается с $04 то тут не всё так однозначно.
$10: Len := 2; //Если следом за $04 идёт $10 длина такого кода будет 3.
else Len := 1 //В любом другом случае 2.
end;
$05: case P^ of //Аналогично поступаем и в этом случае
$FF: Len := 1; //Если следом за $05 идёт $FF длина такого кода будет 2.
else Len := 2 //В любом другом случае 3.
end
end;
X := Length(Str); //
SetLength(Str, X + Len); //
Move(P^, Str[X + 1], Len); //
Inc(P, Len); //Здесь считываем нужное количество байт.
end else
begin
Str := Str + PC^; //Обычное чтение, когда никакие контрольные коды не встретились.
Inc(P)
end
end
end
end; |
Фрагмент таблицы
Код: | 0101=[01_001]
0200=[/C]
0201=[Red]
0202=[Green]
0203=[Blue]
0300DB=[03_045]
0301FE=[03_077]
0301FF=[03_078]
030200=[03_079]
030201=[03_080]
041000=[04_094]
041006=[04_095]
041007=[04_096]
04100C=[04_097]
04100E=[04_098]
0412=[04_099]
0413=[04_100]
0414=[04_101]
0415=[04_102]
050309=[Sw_News_1p1]
05465F=[05_189]
05FF=[05_190]
0600=[Name]
0601=[Choice_1]
0602=[Choice_2]
0603=[Choice_3]
070800=[07_201]
071005=[07_202]
08FF=[08_235]
0900=[09_236]
0978=[09_237]
0C00=[A]
0C01=[B]
0C02=[L]
0C03=[R]
0A
ends
00 |
Совсем недавно увидел ещё более хитрый подход: байт окончания строки 00, системные коды могут не просто его содержать, а с него начинаться(!), но там можно зацепиться за 3-ий байт (вроде всегда одинаковый). Плагин осилил. + Добавился ещё один его собрат.
Код: | Function GetData(TextStrings: PTextStrings): AnsiString; stdcall;
var
R: PTextString;
begin
Result := '';
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <> NIL do
begin
Result := Result + R^.Str + #0; // код конца строки: 00 не отображается в проекте.
R := R^.Next
end
end
end;
Function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
var
P: PByte; PC: PChar absolute P;
Len: Integer; Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
P := Addr(ROM[X]);
while 2+2=4 do //Рыбу оставляем, но шунтируем
begin
Len := 0;
if (P^ = $01) or (P^ = $02) or (P^ = $03)
then begin // Считать 1 байт в строку
Code := P^;
Str := Str + PC^;
Inc(P);
case Code of
$01,
$02,
$03: Len := 1;
end;
X := Length(Str);
SetLength(Str, X + Len);
Move(P^, Str[X + 1], Len);
Inc(P, Len);
end else
if P^ = $00 //Проверяем этот код отдельно
then begin
Inc(P, 2);
Code := P^;
dec(P, 2);
if Code = $0E //Если второй символ после него 0E, то это хитрый код и его нужно записать.
then begin
Str := Str + PC^; Inc(P);
Str := Str + PC^; Inc(P)
end else break //Если нет - конец строки без записи и выход.
end else
begin
Str := Str + PC^;
Inc(P)
end
end
end
end; |
Фрагмент таблицы
Код: | 0E=[0E]
0100=[0_1]
0200=[0_2]
0300=[0_3]
0101=[1_1]
0201=[1_2]
0301=[1_3]
0002=[2_0]
0102=[2_1]
0202=[2_2]
0302=[2_3]
8102=[2_81]
8202=[2_82]
8302=[2_83]
8402=[2_84]
8502=[2_85]
ends
00 |
Тот же тип с той лишь разницей, что здесь всегда будем писать 00, т.к. он является кодом пробела, а раз так, то и код окончания строки - 0000 будет в проекте отображаться.
Код: | Function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
var
P: PByte; PC: PChar absolute P;
Len: Integer; Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
P := Addr(ROM[X]);
while 2+2=4 do //Рыбу оставляем, но шунтируем
begin
Len := 0;
if (P^ = $00) or (P^ = $E5) or (P^ = $E7) or (P^ = $E9)
or (P^ = $EC) or (P^ = $EE) or (P^ = $ED) or (P^ = $F2)
or (P^ = $F4) or (P^ = $F5) or (P^ = $F8) or (P^ = $FB)
or (P^ = $FC) or (P^ = $FF)
then begin // Считать 1 байт в строку
Code := P^;
Str := Str + PC^;
Inc(P);
case Code of
$E5,
$EE,
$F2,
$F5,
$F8,
$FC: Len := 1;
$E7,
$E9,
$EC,
$FF: Len := 2;
$ED,
$FB: Len := 3;
$F4: Len := 5;
$00: case P^ of
$00: begin Str := Str + PC^; break //Конец строки пишем и выходим
end;
else Len := 0 //Т.к. 00, т.е. пробел уже записан.
end;
end;
X := Length(Str);
SetLength(Str, X + Len);
Move(P^, Str[X + 1], Len);
Inc(P, Len);
end else
begin
Str := Str + PC^;
Inc(P)
end
end
end
end;
|
Фрагмент таблицы
Код: | 00=
01=0
02=1
...
E500=!
E501=‼
E502=?
...
E70000=[E700]
E70100=[E701]
E70500=[E705]
E90000=[E900]
F200=[F200]
F404121219FF=[F401]
F500=[F500]
EC0000=[EC00]
ED002200=[ED00]
FB040050=[FB04]
FF0000=[FF00]
E8
EA
EB
ends
0000 |
Вот пример плагина для однобайтовой кодировки c кодами содержащими в себе поле размера (здесь Зельды с GC, Wii и WiiU в которых используются bmg контейнеры для хранения текста: WW, FSA, TP, TP_HD. ):
Код: | Function GetData(TextStrings: PTextStrings): String; stdcall;
Var
R: PTextString;
begin
Result := '';
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <> NIL do
begin
Result := Result + R^.Str + #0; // т.к. код конца строки всего один, можно его и не отображать в проекте.
R := R^.Next
end
end
end;
Function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
var
P: PByte; PC: PChar absolute P;
Len: Byte; Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
P := Addr(ROM[X]);
while P^ <> 0 do
begin
if P^ = $1A then //Более продвинутая система кодов: все начинаются с $1A и содержат в себе размер.
begin
Str := Str + PC^; //Читаем $1A
Inc(P); //Переходим к следующему байту
Code := P^; //Запоминаем байт идущий после $1A, т.к. он и является размером кода.
Str := Str + PC^; //Читаем байт размера в проект
Inc(P); //Переходим к следующему
Len := Code - 2; //Можно прочитать оставшиеся байты в строку (т.к. два байта уже прочитаны от размера отнимаем 2)
X := Length(Str); //
SetLength(Str, X + Len); //
Move(P^, Str[X + 1], Len); //
Inc(P, Len) //Здесь считываем нужное количество байт.
end else
begin
Str := Str + PC^; //Обычное чтение, когда никакие контрольные коды не встретились.
Inc(P)
end
end
end
end;
|
Фрагмент таблицы
Код: | 1A05000000=[Name]
1A0500000D=[L]
1A0500000E=[R]
1A0500000F=[X]
1A05000010=[Y]
1A05000011=[Z]
1A06FF000000=[/c]
1A06FF000001=[Red]
1A06FF000002=[Green]
1A06FF000003=[Blue]
1A06FF000004=[Yellow]
1A06FF000005=[l_Blue]
1A06FF000006=[Purple]
1A06FF000007=[Silver]
1A06FF000008=[Orange]
1A070200060100=[07_101]
1A08020024000101=[08_120]
1A0902000500000166=[09_135]
1A0A0200090000037401=[0A_232]
1A0B020026000000140A01=[0B_312]
1A0C02000D00000032010000=[0C_313]
1A0D02002C000001400000013C=[0D_319]
1A0E020007000000015C0000015C=[0E_327]
1A0F02001002000001C3000001C400=[0F_379]
1A10020023000000000002EF000002EE=[10_423]
1A1102001D000000320000039C0000039B=[11_532]
1A150200180000013A0000013C0000013C0000013D=[15_535]
0A
ends
00 |
Вот пример плагина для двубайтовой кодировки c кодами содержащими в себе поле размера (здесь Зельды NDS: PH и ST в которых используются bmg контейнеры для хранения текста, но текст в Unicode. ):
Код: | function GetData(TextStrings: PTextStrings): AnsiString; stdcall;
var
R: PTextString;
begin
Result := '';
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <> NIL do
begin
Result := Result + R^.Str + #0 + #0; // код конца строки: 0000, можно его и не отображать в проекте.
R := R^.Next
end
end
end;
function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
type
TWordRec = packed record
A, B: Char
end;
var
PW: PWord; PB: PByte absolute PW; PC: ^TWordRec absolute PW;
Len: Word; Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
PW := Addr(ROM[X]);
while PW^ <> 0 do
begin
if PW^ = $001A then //Система кодов с $1A в двубайтовом варианте (Здесь LE).
begin
Str := Str + PC.A + PC.B; // Читаем 2 байта: $001A.
Inc(PW); //Переходим к следующему слову.
Code := PB^; //Запоминаем размер, кодов больше 255 не встречал, поэтому размер здесь определён только 1 байтом.
Str := Str + PC.A + PC.B; //Читаем 2 байта размера в проект
Inc(PW); //Переходим к следующему слову.
Len := Code - 4; //Можно прочитать оставшиеся байты в строку
X := Length(Str); //
SetLength(Str, X + Len); //
Move(PB^, Str[X + 1], Len); //
Inc(PB, Len) //Здесь считываем нужное количество байт.
end else
begin
Str := Str + PC.A + PC.B; //Обычное чтение, когда никакие контрольные коды не встретились.
Inc(PW)
end
end
end
end; |
Фрагмент таблицы
Код: | 1A0006000000=[Ch1]
1A0006FE0000=[Name]
1A0008000A000000=[08_012]
1A0008FF00000000=[/c]
1A0008FF00000100=[Red]
1A0008FF00000200=[Green]
1A0008FF00000300=[Blue]
1A000A000E0014000000=[0A_128]
1A000CFF02000159306A3000=[0C_191]
1A000EFF02000044306130693000=[0E_192]
1A0010FF020001553093304B304F3000=[10_193]
1A00220401000900770069006E0073000000770069006E000000770069006E007300=[Wins]
1A00280401000000740069006D00650073000000740069006D0065000000740069006D0065007300=[Times]
1A002E04010000005200750070006500650073000000520075007000650065000000520075007000650065007300=[Rupees]
1A003404010001007300650063006F006E006400730000007300650063006F006E00640000007300650063006F006E0064007300=[Seconds]
1A0040040100000070006F007300740063006100720064007300000070006F00730074006300610072006400000070006F007300740063006100720064007300=[Postcards]
1A004C04010000007300750062006D0069007300730069006F006E00730000007300750062006D0069007300730069006F006E0000007300750062006D0069007300730069006F006E007300=[Submissions]
0A00
ends
0000 |
Вот пример плагина для двубайтовой кодировки c кодами содержащими в себе поле размера (здесь Зельды SS и WW_HD (UTF-16 BE), ALBW и TFH (UTF-16 LE) в которых используются msbt контейнеры для хранения текста):
Код: | function GetData(TextStrings: PTextStrings): AnsiString; stdcall;
var
R: PTextString;
begin
Result := '';
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <> NIL do
begin
Result := Result + R^.Str + #0 + #0;
R := R^.Next
end
end
end;
function SwapMe2(V: Word): Word;
asm xchg al,ah end;
function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
type
TWordRec = packed record
A, B: Char
end;
var
PW: PWord; PB: PByte absolute PW; PC: ^TWordRec absolute PW;
Len: Word; Code: Word;
begin
New(Result, Init);
with Result.Add^ do
begin
PW := Addr(ROM[X]);
while PW^ <> 0 do
begin
if (PW^ = $000E) or (PW^ = $0E00) then //Двухбайтовая система кодов с $0E (Здесь LE и BE).
begin
if PW^ = $0E00 then Len:=1 else Len:=0; //Используем переменную Len не по назначению: для проверки Endiannes.
Str := Str + PC.A + PC.B; // Читаем 2 байта: $000E или $0E00.
Inc(PW); //Переходим к следующему слову.
Str := Str + PC.A + PC.B; // Читаем 2 байта: они нам не интересны.
Inc(PW); //Переходим к следующему слову.
Str := Str + PC.A + PC.B; // Читаем 2 байта: они нам тоже не интересны.
Inc(PW); //Переходим к следующему слову.
Str := Str + PC.A + PC.B; // Читаем 2 байта: добрались до размера. Он показывает сколько байт в коде ещё осталось прочитать.
Code := PW^; //Запоминаем размер, кодов больше 255 не встречал, но код взял словом (может так правильней).
Inc(PW); //Переходим к следующему слову.
if Len=1 then Len := SwapMe2(Code) else Len := Code; //Сохраняем размер в Len(переводим в LE если нужно).
X := Length(Str); //
SetLength(Str, X + Len); //
Move(PB^, Str[X + 1], Len); //
Inc(PB, Len) //Здесь считываем нужное количество байт.
end else
begin
Str := Str + PC.A + PC.B; //Обычное чтение, когда никакие контрольные коды не встретились.
Inc(PW)
end
end
end
end; |
Фрагмент таблицы BE
Код: | 000E0000000300020000=[Red1]
000E0000000300020001=[Red2]
000E0000000300020002=[Yellow1]
000E0000000300020003=[Blue1]
000E0000000300020004=[Green1]
000E0000000300020005=[Yellow2]
000E0000000300020006=[Violet]
000E0000000300020007=[Green2]
000E0000000300020008=[Blue2]
000E0000000300020009=[Red4]
000E000000030002000A=[Silver]
000E000000030002000B=[Gold]
000E000000030002000C=[Black]
000E000000030002FFFF=[/C]
000E000100000002FFFF=[But1]
000E0001000100020000=[But2]
000E0001000400020001=[Delay01]
000E00010005000400050000=[01_0039]
000E00010006000200CD=[01_0067]
000E000100070004FF000000=[01_0084]
000E00010008000200CD=[01_0085]
000E00010009000400000000=[01_0090]
000E0001000900040000FF05=[01_0253]
000E00010009000400FFFFFF=[01_1118]
000E0001000D00020500=[01_1464]
000E0001000F0000=[01_1467]
000E00010011000201CD=[01_1468]
000E00010012000400000001=[01_1477]
000E000200000000=[Link]
000E0002000100020001=[Item001]
000E00020002000400000000=[Var0]
000E0002000300060000000000CD=[Count01]
000E00020004000200CD=[A]
000E00020004000201CD=[B]
000E000300010000=[03_1677]
000E00030004000201CD=[Bug01]
000E00010005000400000000=[01_003E]
000E0001001000080000045700002EEF=[StaFF]
000A
ends
0000 |
Фрагмент таблицы LE
Код: | 0E000000020002005A00=[00_001]
0E000000030002000900=[Blue]
0E000000030002000A00=[Red]
0E000000030002000B00=[Green]
0E00000003000200FFFF=[/C]
0E00010000000000={Link}
0E00010001000000={Player1}
0E00010002000000={Player2}
0E00010003000000={Player3}
0E000100050006000000000000CD=[01_014]
0E000100050006000000FFFF00CD={count01}
0E0001000600020002CD={choice01}
0E0001000600020003CD={choice02}
0E0001000600020004CD={choice03}
0E000100070002000100=[01_031]
0E0001001100040014002800=[01_061]
0E000200000002000000={-Zelda0-}
0E00020001000400000000CD={-Eastern Palace1-}
0E00020001000400220000CD={-Lost Woods1-}
0E00020002000400580001CD={-Hammer6-}
0A00
ends
0000 |
Единственным недостатком подобных плагинов является то, что поле размера в файлах bmg или msbt не изменяется при пересборке, но это не относится к правильному извлечению\вставке текста. )
+ Плагин другого типа, но весьма полезный для завершения этой статьи, написан на основе примера из доки Griever'a.
Хоть тут и не запаковка, но читается в проект не то, что записано в оригинальном файле, а записывается не то, что хранится в тексте проекта... Но, в итоге, вставка оригинального текста 1в1.
P.S. Для пересчёта длины строк, что находится рядом с указателями, используется отдельная утилитка, стандартными средствами круптара это не сделать, т.к. указатели загружаются из текстового файла, а как это внести в плагин разбираться уже не стал.
Пример плагина для кодировки UTF-8 с выравниванием системных кодов, что используется в Зельдах FSAE и MM3D. (Если не выравнивать, плашки с текстом просто закрываются, хотя в OoT3D, при той же кодировке и системе кодов, такой фигни ещё не было)
В таблице продублируем каждый встреченный не выровненный системный код выровненным и наоборот.
Для удобства расчётов и красоты текста в проекте, выровненные коды которые уже есть в оригинале будем читать как не выровненные, ибо нефиг.
Код: | Function GetData(TextStrings: PTextStrings): String; stdcall;
Var
R: PTextString;
I, J: integer;
begin
Result := '';
I := 1; \\ Счётчик записываемых символов
J := 0; \\ Счётчик дополнительных 00
If TextStrings = NIL then Exit;
With TextStrings^ do
begin
R := Root;
While R <NIL> Length(Str) then \\ Когда счётчик записываемых символов стал длиннее строки
begin Result := Result + #127 + #0 + #0; break \\ Пишем результат, добавляем к нему символ конца строки, брякаем цикл.
end;
if Byte(Str[I]) = $7F then \\ Если записали первый символ системного кода, то
if (I + J) mod 2 <>0 then \\ Если позиция $7F нечет, то
begin Result := Result + Char(Str[I]) + #0; Inc(I); Inc(J) end \\ Добавляем 00 и увеличиваем оба счётчика на 1.
else begin Result := Result + Char(Str[I]); Inc(I) end \\ Иначе, если чёт, просто записываем символ и инкрементим только счётчик I.
else begin Result := Result + Char(Str[I]); Inc(I) end; \\ А если не код $7F, то просто пишем символ и инкрементим счётчик.
until false \\ Всё это продолжается пока цикл не брякнется.
end;
R := R^.Next
end
end
end;
Function GetStrings(X, Sz: Integer): PTextStrings; stdcall;
var
P: PByte; PC: PChar absolute P;
Code: Byte;
begin
New(Result, Init);
with Result.Add^ do
begin
P := Addr(ROM[X]);
while 2+2=4 do \\ Покуда не брякнемся
begin
if P^ = $7F then \\ Если видим первый символ системного кода, то
begin
Inc(P); \\ Посмотрим кто стоит за ним
Code := P^;
Inc(P);
case Code of
$00: case P^ of \\ Если это ноль
$00: break; \\ А за ним ещё ноль, то это конец строки, выходим не читая.
else begin \\ Если за нулём идёт что-то другое, то ноль мы пропускаем не читая, а $7F и это что-то прочтём.
Dec(P,2); Str := Str + PC^;
Inc(P,2); Str := Str + PC^;
Inc(P)
end
end;
else begin \\ Если не ноль
Dec(P,2); Str := Str + PC^; \\ Читаем все оба два.
Inc(P); Str := Str + PC^;
Inc(P)
end
end;
end else \\ Если не код, то обычное чтение.
begin
Str := Str + PC^;
Inc(P)
end
end
end
end; |
Фрагмент таблицы
Код: | 41=A
42=B
43=C
44=D
45=E
...
61=a
62=b
63=c
64=d
65=e
...
D090=А
D091=Б
D092=В
D093=Г
D094=Д
D095=Е
...
D0B0=а
D0B1=б
D0B2=в
D0B3=г
D0B4=д
D0B5=е
...
7F0A000100=[A]
7F000A000100=[A+]
7F0A000200=[B]
7F000A000200=[B+]
7F0A000300=[X]
7F000A000300=[X+]
7F0A000400=[Y]
7F000A000400=[Y+]
7F0A000500=[L]
7F000A000500=[L+]
7F0A000600=[R]
7F000A000600=[R+]
7F0A000900=[D-Pad]
7F000A000900=[D-Pad+]
7F0E00=[7F_068]
7F000E00=[7F_068+]
7F11000000=[/C]
7F0011000000=[/C+]
7F11000100=[Red]
7F0011000100=[Red+]
7F11000300=[Blue]
7F0011000300=[Blue+]
7F0100
7F000100
7F0200
7F000200
ends
7F0000 |
Если сложилось впечатление, что Kruptar подходит исключительно для перевода серии Zelda, то это неверное впечатление...
Последний раз редактировалось: Chime[RUS] (Сб Июл 29, 2017 4:35 pm), всего редактировалось 18 раз(а) |
|