Эти пояснения предназначены для всех, кто хочет КАЧЕСТВЕННО переводить игры для приставок NES и SNES.
ВСТУПЛЕНИЕ
Первое, что хочу сказать, это то, что дока эта еще относительно сырая и малоинформативная. НО, это только первая версия, и я в последствие многое в ней я буду дополнять и менять. А для скорейших и нужных вам изменений, присылайте мне ваши отзывы об этой доке: чего-то не хватает, что-то не понятно, о чем-то мало сказано и хотелось бы узнать побольше, или же я в чем-то ошибся и т.д. В общем, пишите!
Итак, для начала, многие из вас, наверное, слышали о пойнтерах, многие даже знают, что это такое :-))), но не все знают как ими пользоваться. А тем, кто не знает, могу сказать только одно - они позволяют менять длину строки, и делать строку длиннее, чем она была изначально, это может пригодиться, если по-русски перевести какую-то фразу не возможно, так как не влазишь в отведенное под нее место(например, как бы вы перевели фразу "If I sad no?", сохранив такую же длину? :-)). Но я сразу хочу заметить для всех - пойнтеры НЕ дают вам неограниченного места! Менять длину строки можно ТОЛЬКО(если в самом РОМе ничего не менять) с условием, что вы настолько же укоротите какую-нибудь другую строку, так как место под текст в РОМе ограничено уже имеющимся текстом. Это правило действует НЕ всегда, но такие случаи скорее исключение, чем правило.
И еще, т.к. я разбирался с пойнтерами по доке " THE MADHACKER'S GUIDE TO NES POINTERS ", то я многое брал из нее, т.к. в ней достаточно понятно все изложено и я думаю ни к чему изобретать велосипед и придумывать какое-нибудь другое объяснение, но это, конечно, не значит, что я просто пишу здесь ее перевод, просто какие-то части моего объяснения могут совпадать(и это не случайное совпадение) с этой докой.
ЧТО ВАМ ДЛЯ ЭТОГО ПОНАДОБИТСЯ
Hexposure v0.44b, знание работы с 16-ричными редакторами и естественно шестнадцатеричной системой исчисления, много свободного времени и главное ТЕРПЕНИЕ, ну и конечно переводимый вами РОМ :-))).
ВСТУПЛЕНИЕ
Итак, что же такое пойнтеры? -, спросят не знающие люди. Попросту говоря, это байт(вернее, два байта), указывающий где в РОМе расположена какая-то конкретная строка. Для знающих BASIC могу привести такой пример:
10 Print "Это игровой текст"
20 Goto 10
В рассмотренном примере команда Goto 10 и является пойнтером, то есть указателем(to point - указывать) на то место где расположен текст - в данном случае это текст команды Print. Естественно, что и команд Print и Goto может быть и больше и сама программа посложнее, но, надеюсь, суть вы поняли. А для людей, не знающих Бэйсик могу привести такой пример: вы, наверное, не раз видели в книгах такую надпись <ст. 193, 2 обзац, 3 предложение.>, ну или что-то наподобие того, так вот это тоже своего рода пойнтер. Сразу хочу сказать, что пойнтеры для NES (далее буду называть Денди - для меня это как-то <роднее> звучит :-))) и SNES - ДВУХБАЙТНЫЕ. Запомнить это очень важно. Итак сейчас важно усвоить - Пойнтеры - это двухбайтные шестнадцатеричные значения, предназначенные для указания расположения в РОМе какой-то конкретной строки или участка текста.
ВЫЧИСЛЕНИЕ И НАХОЖДЕНИЕ ПОЙНТЕРОВ
Итак, суть и назначение пойнтеров мы поняли, теперь нам необходимо их найти. Для начала я расскажу, как это делается в РОМах Денди, а на СНЕС остановлюсь немного позже. Хочу сразу сказать, что систем у пойнтеров много, но суть этих систем всегда одна. И еще, я сам о пойнтерах знаю без году неделю, поэтому я пишу здесь только основы, то, в чем сам разобрался. По мере моего дальнейшего изучения пойнтеров и набирания опыта, я буду дополнять этот док.
Так как для более понятного объяснения необходим пример, то я возьму в качестве примера игру Final Fantasy 1, английскую версию. Думаю, что если вы уже интересуетесь пойнтерами, то вам не составит труда приготовить таблицу ;-)). Итак, надеюсь, вы все приготовили и готовы продолжать читать. Для начала вы должны запомнить, что от всех адресов надо отнимать 10h байт. Поясню, у КАЖДОГО РОМа в начале файла записан так называемый хедер(header), в нем содержится информация системного характера(меппер, размер CHR и PRG и т.д.), он занимает 10 байт в 16-ричной системе исчисления(и далее все адреса и значения я буду указывать именно в ней), а так как в настоящих картриджах такого хедера нет, то все значения при вставке в сдампленный с картриджа РОМ хедера сдвигаются. Эмуляторы при прочтении РОМа загружают его в оперативку уже без хедера, поэтому этот сдвиг не вызывает никаких ошибок. Но при работе с РОМом размер хедера ВСЕГДА надо учитывать и ВСЕГДА отнимать от любых адресов(например, адрес $29F024 на самом деле является адресом $29F014). Теперь, наконец-то, перейдем к практическому высчитыванию пойнтеров. Как я уже говорил выше, существуют разные типы пойнтеров, но система одна. Для удобства понимания, я разобью ее на две системы(хотя, технически система одна, запомните!):
Standart Header
SetOff X000
Standart Header
Самая простая как для высчета, так и для нахождения. К сожалению, она встречается в РОМах не так часто как хотелось бы.
А сейчас внимание! Сейчас я буду рассказывать основы пойнтеров, поэтому советую в этом месте ушами не хлопать :))).
Итак, откройте в Hexposure РОМ Final Fantasy 1, и найдите фразу "Nothing here."(если в лом искать, то она находится по адресу $28210), эту фразу легко встретить в игре, поэтому мы ее и возьмем. И запомните: пойнтер указывает на первую букву строки, то есть, на следующий после байта <конец строки>, байт - это и есть место, на которое указывает пойнтер. Итак, ваши дальнейшие действия состоят из следующих шагов:
Начальный адрес $28210
Отнять 10h: 28210 à 28200
Убрать все цифры до тысячных: 28200 à 8200
Мысленно разделить это число на две пары: 8200h à 82 00
Теперь поменять эти пары местами: 82 00 à 00 82
И также мысленно соединить пары обратно: 00 82 à 0082
И вот он, ваш пойнтер: 0082
Небольшие пояснения, насчет отнятия 10h от адреса надеюсь все понятно, а вот насчет убирания чисел до тысячных, то это сделано именно потому, что Денди использует двухбайтные пойнтеры, это значит, что адреса $34F567 и $123F567 одинаковы, т.к. в обоих случаях пойнтером будет число 57F5(с учетом хедера естественно). Отсюда вытекает очень важное правило: каждый пойнтер действует только в пределах 10000h. Это значит, что в примере с FF1 пойнтер потенциально может указывать только на тот текст, который находится ТОЛЬКО в между адресами $20010 и $3001F(ну, или $20000 и $2FFFF, если считать хедер). Поэтому вы сможете писать строку где угодно, но в указанных пределах. И запомнить это очень важно! А почему пары меняются местами я точно не знаю, но их ВСЕГДА надо менять местами, и это тоже надо запомнить.
Теперь самая сложная часть - найти расположение этого пойнтера. Здесь понадобится эмулятор(я рекомендую Nester, т.к. он в данном случае очень удобен: можно ассоциировать его с файлами .nes и запускать простым кликом по файлу, он запускается в окне и запускается довольно быстро, к тому же загружать сейвы можно простым перетаскиванием иконки файла сейва в окно эмулятора, да и по совместимости он в рядах лидеров). Для того чтобы найти пойнтер вам возможно придется перебрать множество перепробовать много разных адресов, т.к. значений 0082 в РОМе много, а пойнтер такой только один. Итак, в Hex search вводим значение 0082 и ищем. Итак, значение найдено, но это вовсе не значит, что это и есть ваш пойнтер, попробуйте поменять это значение на какое-нибудь другое(например, высчитайте пойнтер какой-нибудь другой строки и напишите его). Затем сохраните изменения(думаю о резервном копировании мне напоминать ни к чему :-)), запустите игру в эмуляторе и вызовите эту строку(просто находясь в городе нажать <А>). Если надпись изменилась - поздравляю, вы нашли пойнтер, если же нет, то закрывайте эмулятор, меняйте измененное вами значение обратно, и ищите дальше, и через некоторое время вы ОБЯЗАТЕЛЬНО найдете ваш пойнтер!
И так во всех играх, но только, если вы сделали все правильно, но не нашли пойнтер(т.е. искомая строка так и не изменилась), то вы похоже, столкнулись с вышеупомянутой системой SetOff X000.
SetOff X000
Уже сложнее, но встречается гораздо чаще. В принципе это тоже самое, что и Standart Header, за исключением еще одного шага в при вычислении пойнтера(учтите, что в FF1 используется система Standart Header!!! Просто для удобства восприятия, я оставил для примера адрес из нее, и в дальнейшем я, пожалуй, в качестве примера и продолжу его использовать):
1. Начальный адрес $28210
2. Отнять 10h: 28210 à 28200
3. Прибавить к тысячным значение Х000: (если, к примеру, Х=3) 28200 à 31200
4. Убрать все цифры до тысячных: 31200 à 1200
5. Мысленно разделить это число на две пары: 1200 à 12 00
6. Теперь поменять эти пары местами: 12 00 à 00 12
7. И также мысленно соединить пары обратно: 00 12 à 0012
8. И вот он, ваш пойнтер: 0012
Как вы заметили, шаг то добавился один, а число получилось другое. Все дело здесь в том, что значение первой цифры второго байта пойнтера пойнтера по каким-то причинам изменено на определенное количество шагов, то есть к ней прибавлено какое-то число. Для чего это сделано я не знаю, но это порой сильно затрудняет поиск. Если вы не знаете значение Х, то поиск надо вести следующим способом:
Вычислите пойнтер строки по системе Standart Header
В полученном значении мысленно замените первую цифру второго байта на Х: т.е. если пойнтер 452A, то представьте его как 45XA. Теперь в Hex search, ищите 45. Как вы понимаете, результатов будет очень много, но тут есть маленькая зацепка: при нахождении 45, посмотрите на байт СПРАВА от него, если в нем ВТОРАЯ цифра А, то это вполне вероятно и есть ваш пойнтер. Какой-то конкретный пример из игры я привести пока не могу, но попытаюсь объяснить, что называется <на пальцах> :))). Итак, скажем, ваш начальный адрес $453A1B, отнимаем 10h, убираем 45, меняем пары местами и получаем 0B3A. Теперь в поиске ищем 0B, и найдя его смотрим на байт справа, допустим мы нашли его и справа от него байт 45, тогда это заведомо НЕ пойнтер, т.к. вторая цифра этого байта не А. Продолжаем искать, отбрасывая заведомо неправильные варианты, пока наконец не столкнемся с чем-то наподобие 0B6A, это уже потенциальный пойнтер, т.к. вторая цифра А, поэтому его надо проверить, напишите вместо 0B какое-нибудь(любое) число, сохранитесь, и попробуйте запустить игру в эмуляторе. Если строка, пойнтер которой вы хотели изменить, изменилась, то вы нашли пойнтер, отнимайте от 6A 3A, т.е. от шести отнимите три, это и будет ваш Х. То есть значение SetOff у этой игры будет SetOff 3000. Такая система работает в абсолютном большинстве случаев, но если уж и она не поможет, то остается один вариант - искать и проверять ВСЕ байты 0B(в ОЧЕНЬ редких случаях используется однобайтная система, если столкнетесь с ней, советую забить на игру в которой она вам попалась, т.к. поиски и проверки, тем более если игра весит несколько мегов, займет ОЧЕНЬ много времени).
ТАБЛИЦЫ ПОЙНТЕРОВ
Как вы знаете, текст в играх чаще всего расположен блоками. В блоках строки идут одна за другой, и разделены они каким-нибудь байтом, обозначающим конец строки. Так вот, пойнтеры очень часто(особенно в таких играх как РПГ) расположены такими же блоками, даже последовательность имеют ту же, что и строки в текстовом блоке. Если в переводимом вами РОМе текст расположен блоками и вы уже нашли пойнтер какой-то строки из этого блока, попробуйте высчитать пойнтер следующей строки, затем найдите то место, где расположен уже найденный вами пойнтер предыдущей строки и посмотрите на два байта справа от него, если они такие же как и ваш пойнтер, то здесь и есть ваша таблица пойнтеров. Когда пойнтеры расположены таблицей менять длины строк в текстовом блоке легко, т.к. изменив длину какой-то строки(и высчитав при этом ее пойнтер), вы находите адрес, на котором теперь начинается следующая строка, вычисляете ее новый пойнтер и просто вписываете новый пойнтер за место того пойнтера, который был справа от пойнтера строки, длину которой вы изменили.
Короче, чтобы не грузить вас, приведу наглядный пример:
В FF1 по адресу 28010(как вы уже, наверно, вычислили, это и есть адрес, по которому расположен пойнтер строки "Nothing here") идет такая строка:
0082 0982 5C82 BD82 D982 3083 5383 D183
А теперь идите на то место, где написана строка "Nothing here", и попробуйте высчитать пойнтеры следующих за ней строк(не забывая, конечно, что следующая строка начинается после байта <конец строки>, и про хедер, конечно же, тоже), и теперь сравните их с указанной строкой. Видите? Все просто!!!
ПОЙНТЕРЫ SNES
На самом деле система пойнтеров у СНЕСа практически точно такая же как и у Денди, за исключением того, что в отличии от Денди, размер хедера у РОМов СНЕСа равен 200h байт. То есть вся разница в том, что отнимать надо не 10h, а 200h. Но здесь надо сделать важное замечание: у СНЕСа не всегда нужно отнимать размер хедера. Иногда вообще ничего отнимать не надо, а иногда нужно что-то отнять, но неизвестно что(в таком случае можно сказать, что вам не повезло :-))).
СЛУЧАИ, КОГДА ПОЙНТЕРЫ БЕСПОЛЕЗНЫ
Вы, наверное, не раз замечали, что можно в некоторых играх свободно менять длину строки просто поставив байт <конец строки> и писать дальше следующую строку. Этот тип текста называется SEQUENTIAL TEXT. Тут вам пойнтеры не нужны, вы и сами можете менять длину строки, но помните, что менять их чаще всего можно только в пределах диалога, или сцены, или еще какого-то события, а на следующий диалог, сцену, событие уже пойнтером указывается расположение первой строки.
Другая система, это FIXED LENGTH. Суть ее в том, что в программном коде указано, не только расположение строки, но и ее длина. Это значит, что даже при всем желании длину какого-то слова вам не увеличить(по крайней мере, не зная ассемблер). Для текста эта система почти не используется, но довольно часто встречается в менюшках, в частности, в серии Final Fantasy. Явным признаком этой системы является отсутствие байта <конец строки> между словами. Заданная длина одинакова для всех строк в этой системе, и обычно бывает равна 8, или 16 символам.
НЕКОТОРЫЕ РЕКОМЕНДАЦИИ И ЗАМЕЧАНИЯ
Если вы ищете строку из таблицы, то попробуйте пару способов, которые действуют не всегда и не везде, но если действуют то очень сокращают время поисков. Во-первых, помните, что если вы ищете строку из блока, то вполне вероятно, что в РОМе есть таблица пойнтеров с аналогичным строкам из блока расположением пойнтеров, в таком случае просто вычислите пойнтер этой и следующей строки, и в поиске напишите их вместе(например, если первый пойнтер 489C, а второй 529С, то просто введите 489C529C), при этом ВЕЛИКА вероятность, что пойнтер вы найдете с первой же попытки. Этот способ не работает с текстовыми блоками с диалогами из FF5, да и со многими другими играми тоже. Во-вторых, таблица пойнтеров довольно часто находится близко, или вообще над текстовым блоком, проверьте, это также сможет сэкономить время.
И еще, поищите программу A Simple Pointer Table Recalculator(по-моему, она была где-то на Zophar`е), она очень помогает, если надо пересчитывать всю таблицу пойнтеров(например, если вставили текст), а заниматься этим в лом чугунный :-))). Программа эта помогает не всегда, но иногда просто незаменима.
Прежде чем писать мне на мыло, учтите, что:
Я не буду присылать или принимать от вас РОМы(не касается это только участников группы <ШЕДЕВР>).
Я знаю, что вы хотите знать про пойнтеры Сеги, я тоже хочу :-)).
Я не занимаюсь никакими черными делами :-)))).
Не стоит мне писать всякую чушь.
И не надо меня кучу раз спрашивать когда выйдет новая версия дока - как только, так сразу :-))).
И еще, я не буду иметь никаких претензий, если вы будете использовать этот док для некоммерческих целей, но любое коммерческое использование без моего ведома, или ведома группы запрещено!
1448 Прочтений • [Пойнтеры v 1.0] [07.08.2012] [Комментариев: 0]