Guyver
Боже мой, на каком языке вы говорите??? На земном??? <;о)
31. Guyver - 11 Февраля, 2016 - 08:24:59 - перейти к сообщению
32. Griever - 11 Февраля, 2016 - 08:25:37 - перейти к сообщению
Griever
ОК, ты меня навёл на правильную мысль. Теперь я имею право сказать: "ЗНАЧИТ ТАК:" =Р
Есть такой байт 5, ты, наверное, уже о нём думал =) Это счётчик уже выведенных на экран тайлов из карты. Так вот те два сравнения относятся только к пятерке и вообще никакого отношения не имеют не к внутреннему ни к внешнему циклам. В самом начале в два контрольных байта(8 и 9) загружаются значения. выводится первый символ, который был считан ранее. Проверяется старший бит девятки. Ну, как уже говорилось, если единичка, то знак повторяется, если ноль - читается следующий. и так далее, пока у нас не "исшифтуется" девятка. А шифтуется она в любом случае, даже если выводятся два одинаковых тайла. Это значит, что к моменту, когда девятка кончится в пятерке станет $#08. На этот случай есть команда по адресу $8117, которая проверяет кратность счётчика(пятерки) числу восемь. И если у нас девятка исшифтовалась, то мы один разик шифтуем восьмёрку и если в восьмёрке ноль, то девятку мы не читаем, а оставляем такой же какой она стала (а осталась она с нулями), а уже в подпрограмме
вывода индекса тайла девятку мы не шифтуем, а просто постоянно считываем по одному индексу тайла из РОМа. Одним словом, если восьмерочный бит ноль, то следующие восемь тайлов будут без повторов.
Таким образом, мы в конце концов исшифтуем и восьмерку. К тому времени в счётчике тайлов будет $#40, тут уже сработает команда $8102 - которая позволит нам считать из рома новое значение восьмёрки, если порядковый номер следующего тайла будет кратен #$40. И всё повторится сначала.
Вот и всё. Остается писать пакер/анпакер, что представляет большую проблему по сравнению с другими алгоритмами: приходится учитывать счетчик тайлов ВСЕЙ карты, а значит распаковка обязательна
целиком - по частям нельзя. Как и запаковка.
И вот ещё:
На самом деле, если из восьмерки перемещается ноль, то что в девятке уже неважно(см. выше) - байты пойдут без повторов.
Ещё, если посмотреть внимательнее, то надписи на экранах типа "Where shall we go today?" тоже пережаты этим алгоритмом.
Гайверу виднее: может где ещё. Так что с этой игрой ещё кувыркаться и кувыркаться =Р
PS: хотел написать распаковщик, но у самого переводы стоят =)
ОК, ты меня навёл на правильную мысль. Теперь я имею право сказать: "ЗНАЧИТ ТАК:" =Р
Есть такой байт 5, ты, наверное, уже о нём думал =) Это счётчик уже выведенных на экран тайлов из карты. Так вот те два сравнения относятся только к пятерке и вообще никакого отношения не имеют не к внутреннему ни к внешнему циклам. В самом начале в два контрольных байта(8 и 9) загружаются значения. выводится первый символ, который был считан ранее. Проверяется старший бит девятки. Ну, как уже говорилось, если единичка, то знак повторяется, если ноль - читается следующий. и так далее, пока у нас не "исшифтуется" девятка. А шифтуется она в любом случае, даже если выводятся два одинаковых тайла. Это значит, что к моменту, когда девятка кончится в пятерке станет $#08. На этот случай есть команда по адресу $8117, которая проверяет кратность счётчика(пятерки) числу восемь. И если у нас девятка исшифтовалась, то мы один разик шифтуем восьмёрку и если в восьмёрке ноль, то девятку мы не читаем, а оставляем такой же какой она стала (а осталась она с нулями), а уже в подпрограмме
вывода индекса тайла девятку мы не шифтуем, а просто постоянно считываем по одному индексу тайла из РОМа. Одним словом, если восьмерочный бит ноль, то следующие восемь тайлов будут без повторов.
Таким образом, мы в конце концов исшифтуем и восьмерку. К тому времени в счётчике тайлов будет $#40, тут уже сработает команда $8102 - которая позволит нам считать из рома новое значение восьмёрки, если порядковый номер следующего тайла будет кратен #$40. И всё повторится сначала.
Вот и всё. Остается писать пакер/анпакер, что представляет большую проблему по сравнению с другими алгоритмами: приходится учитывать счетчик тайлов ВСЕЙ карты, а значит распаковка обязательна
целиком - по частям нельзя. Как и запаковка.
И вот ещё:
Цитата:
Внутренний же цикл очень прост: если из восьмого контрольного байта в флаг перемещается ноль, а из девятого - единица, или из восьмого - единица, а из девятого - ноль, то происходит вычисление нового кода, в противном случае происходит происходит копирование предыдущего.
На самом деле, если из восьмерки перемещается ноль, то что в девятке уже неважно(см. выше) - байты пойдут без повторов.
Ещё, если посмотреть внимательнее, то надписи на экранах типа "Where shall we go today?" тоже пережаты этим алгоритмом.
Гайверу виднее: может где ещё. Так что с этой игрой ещё кувыркаться и кувыркаться =Р
PS: хотел написать распаковщик, но у самого переводы стоят =)
33. alex_231 - 11 Февраля, 2016 - 08:26:00 - перейти к сообщению
alex_231
Ты меня не так понял.
Я сделал вывод о циклах как раз по пятому байту, но циклы эти организуются в высокоуровневом языке, а в ассемблере вычисления производятся аналогично циклу, но самого цикла как такового там нет.
Не согласен, я писал без учета количества разжатых тайлов (если только циклы не считать средством учета), да и пак/анпак по частям тоже возможен, но только вручную.
А вообще - верно, с повтором я намудрил
Декомпрессор готов.
Щас за пакер возьмусь.
Цитата:
Есть такой байт 5, ты, наверное, уже о нём думал =) Это счётчик уже выведенных на экран тайлов из карты. Так вот те два сравнения относятся только к пятерке и вообще никакого отношения не имеют не к внутреннему ни к внешнему циклам.
Ты меня не так понял.
Я сделал вывод о циклах как раз по пятому байту, но циклы эти организуются в высокоуровневом языке, а в ассемблере вычисления производятся аналогично циклу, но самого цикла как такового там нет.
Цитата:
Остается писать пакер/анпакер, что представляет большую проблему по сравнению с другими алгоритмами: приходится учитывать счетчик тайлов ВСЕЙ карты, а значит распаковка обязательна
целиком - по частям нельзя. Как и запаковка.
целиком - по частям нельзя. Как и запаковка.
Не согласен, я писал без учета количества разжатых тайлов (если только циклы не считать средством учета), да и пак/анпак по частям тоже возможен, но только вручную.
А вообще - верно, с повтором я намудрил
Декомпрессор готов.
Щас за пакер возьмусь.
34. alex_231 - 11 Февраля, 2016 - 08:26:20 - перейти к сообщению
alex_231
Griever, а может пока я пакер пишу ты разберёшься, как программа определяет когда пора заканчивать распаковку, а то я сделал по адресам, но это не совсем правильно, так как в роме есть указатель только на начало пакета, а конец как-то вычисляется.
Griever, а может пока я пакер пишу ты разберёшься, как программа определяет когда пора заканчивать распаковку, а то я сделал по адресам, но это не совсем правильно, так как в роме есть указатель только на начало пакета, а конец как-то вычисляется.
35. alex_231 - 11 Февраля, 2016 - 08:27:01 - перейти к сообщению
alex_231
Эх, ну я и размахнулся, готов пакер, проверил - работает, правда иногда подглючивает, но как-то странно:
нижеуказанные комбинации после разжатия в игре (позже: хотя и декомпрессор так же разжимает, значит это глюк пакера ) выглядят так:
D8 40 D4 --> D8 D8 D4
E8 40 E4 --> E8 E8 E4
F8 40 F4 --> F8 F8 F4
но если заменить 40 на 00 то всё проходит как должное.
Интересно, в чём же его проблема?
А вот что получилось в результате (это я так, шутя):
Эх, ну я и размахнулся, готов пакер, проверил - работает, правда иногда подглючивает, но как-то странно:
нижеуказанные комбинации после разжатия в игре (позже: хотя и декомпрессор так же разжимает, значит это глюк пакера ) выглядят так:
D8 40 D4 --> D8 D8 D4
E8 40 E4 --> E8 E8 E4
F8 40 F4 --> F8 F8 F4
но если заменить 40 на 00 то всё проходит как должное.
Интересно, в чём же его проблема?
А вот что получилось в результате (это я так, шутя):
36. Guyver - 11 Февраля, 2016 - 08:27:23 - перейти к сообщению
Guyver
Круто! Там в игре как минимум штук 6 таких экранов - этот, 3 экрана когда выбираешь в какой порт плыть, когда поймаешь огромную рыбу типа марлина (любого вида) или акулы и взвесишь её в порту и ещё...
Игра здоровская, будет просто замечательно, если удастся её перевести на русский язык...
Круто! Там в игре как минимум штук 6 таких экранов - этот, 3 экрана когда выбираешь в какой порт плыть, когда поймаешь огромную рыбу типа марлина (любого вида) или акулы и взвесишь её в порту и ещё...
Игра здоровская, будет просто замечательно, если удастся её перевести на русский язык...
37. alex_231 - 11 Февраля, 2016 - 08:27:47 - перейти к сообщению
alex_231
На первый взгляд там 10 указателей на такие экраны, но это еще проверить нужно.
На первый взгляд там 10 указателей на такие экраны, но это еще проверить нужно.
38. Guyver - 11 Февраля, 2016 - 08:28:26 - перейти к сообщению
Guyver
Когда я писал верхний пост, то сначала написал "Там в игре 10 таких экранов", но потом подумал что могу ошибаться - давно не играл, и написал "как минимум штук 6"... Вот ведь как бывает ;о)
Когда я писал верхний пост, то сначала написал "Там в игре 10 таких экранов", но потом подумал что могу ошибаться - давно не играл, и написал "как минимум штук 6"... Вот ведь как бывает ;о)
39. Griever - 11 Февраля, 2016 - 08:28:58 - перейти к сообщению
Griever
Хорошо, если тебе всё ещё это интересно, то пожалуйста:
По адресу $a2d5 (если ты помнишь, это перед самым началом нашей тайловой карты) есть два байта: $1E и $3E. Они XOR'ятся и получается $20 - объём извлекаемых данных, характерный для этой карты(не знаю, почему именно двадцать и почему нельзя распаковать сразу весь экран). Он сохраняется в ячейку $02 и $304. Первая используется при копировании уже распакованных данных в PPU, а вторая - при первичной распаковке в RAM. И потом командой по адресу 8037 в первом случае и С338 во втором постоянно сравнивается с нулём после декремента. Казалось бы: почему $20, ведь экран
на NES состоит из 32*20 тайлов? На самом деле после распаковки 32-х тайлов в RAM, их сразу сбрасывают в PPU. Поэтому распаковка осуществляется этакими "блоками" по 32 тайла. Значит экран будет заполнен после тридцати таких "итераций" (учёба в вузе пополнила мой лексикон =)) Так вот, в принципе, можно поставить счётчик на блоки, и закончить распаковку на тридцатом блоке. Ну ещё можно поставить условие, что если в 304 будет записано не $20, а $08, то распаковка должна закончиться. В отношении нашей карты я встретил такую ситуацию, когда производилось чтение из рома по адресу $A461.
Не знаю точно - сработает ли, но конец карты должен быть именно там. Эта ситуация объясняется тем что после распаковки тайловых карт сразу начинается распаковка таблиц аттрибутов(23с0-2400), которая в свою очередь
скидывается в PPU в блоках по 8 (восемь итераций). Поэтому, как только начинается распаковка аттрибутов - прекращаем распаковку.
Примечательно что в ячейках $301 и $302 содержится адрес PPU, относящийся к области тайловых карт, с которого следует возобновить
распаковку индексов. Причём они не загружаются из рома, а к ним прибавляется постоянно число $20, которое предварительно
берётся из рома по адресу $a29d
Цитата:
Griever, а может пока я пакер пишу ты разберёшься, как программа определяет когда пора заканчивать распаковку, а то я сделал по адресам, но это не совсем правильно, так как в роме есть указатель только на начало пакета, а конец как-то вычисляется.
Хорошо, если тебе всё ещё это интересно, то пожалуйста:
По адресу $a2d5 (если ты помнишь, это перед самым началом нашей тайловой карты) есть два байта: $1E и $3E. Они XOR'ятся и получается $20 - объём извлекаемых данных, характерный для этой карты(не знаю, почему именно двадцать и почему нельзя распаковать сразу весь экран). Он сохраняется в ячейку $02 и $304. Первая используется при копировании уже распакованных данных в PPU, а вторая - при первичной распаковке в RAM. И потом командой по адресу 8037 в первом случае и С338 во втором постоянно сравнивается с нулём после декремента. Казалось бы: почему $20, ведь экран
на NES состоит из 32*20 тайлов? На самом деле после распаковки 32-х тайлов в RAM, их сразу сбрасывают в PPU. Поэтому распаковка осуществляется этакими "блоками" по 32 тайла. Значит экран будет заполнен после тридцати таких "итераций" (учёба в вузе пополнила мой лексикон =)) Так вот, в принципе, можно поставить счётчик на блоки, и закончить распаковку на тридцатом блоке. Ну ещё можно поставить условие, что если в 304 будет записано не $20, а $08, то распаковка должна закончиться. В отношении нашей карты я встретил такую ситуацию, когда производилось чтение из рома по адресу $A461.
Не знаю точно - сработает ли, но конец карты должен быть именно там. Эта ситуация объясняется тем что после распаковки тайловых карт сразу начинается распаковка таблиц аттрибутов(23с0-2400), которая в свою очередь
скидывается в PPU в блоках по 8 (восемь итераций). Поэтому, как только начинается распаковка аттрибутов - прекращаем распаковку.
Примечательно что в ячейках $301 и $302 содержится адрес PPU, относящийся к области тайловых карт, с которого следует возобновить
распаковку индексов. Причём они не загружаются из рома, а к ним прибавляется постоянно число $20, которое предварительно
берётся из рома по адресу $a29d
40. alex_231 - 11 Февраля, 2016 - 08:29:17 - перейти к сообщению
alex_231
Ну, блоки я и сам видел, а вот то, что их должно быть двадцать как-то не догадался, но это погоды не делает придётся так оставить, по адресам.
Ну, блоки я и сам видел, а вот то, что их должно быть двадцать как-то не догадался, но это погоды не делает придётся так оставить, по адресам.
41. Griever - 11 Февраля, 2016 - 08:29:52 - перейти к сообщению
Griever
Ну я и написал это для того, чтобы показать, что у алгоритма нет какого-то кода завершения распаковки. А вообще - можно, наверное, просто отследить загрузку вомьмерки(см. выше)
Ну я и написал это для того, чтобы показать, что у алгоритма нет какого-то кода завершения распаковки. А вообще - можно, наверное, просто отследить загрузку вомьмерки(см. выше)
42. Mefistotel - 11 Февраля, 2016 - 08:32:26 - перейти к сообщению